What would be the proper (non "hacky") way of setting samplerates way below the current, say 8kHz or even less. I'd like to know because i will need as much as processingtime per frame as possible on my bela when using puredata. would libpd be ok with those lower Samplerates? is the codec adjusting anti alliasing filters on its own?
Apart from that, would it be possible to go even lower on the blocksize of puredata maintaining lowest possible latency even with lower samplerates?
the optimal setting for me would be 1000 khz SR at blocksizes of 1. Can that be achieved with libpd?

    Hi alaimodiloro ,
    this is an interesting question.
    The settings of the audio codec are initialized in core/I2c_codec.cpp, in the I2c_Codec::startAudio method.
    Working your way through the code comments there, paired with a thorough look at the codec's datasheet should allow you to understand which registers you want to change to obtain a lower sampling rate.
    If you do not want to mess around with the core code, some of these registers could be overridden the first time you run render() if needed ( see e.g.: here), though I am not sure you can get away with completely re-init'ing the codec here (i.e.: editing core/I2c_codec.cpp may be the only possible way to go).
    The codec nominally supports sample rates from 8kHz to 96kHz, so I am not sure you can achieve 1kHz.

    Regarding libpd, the minimum block size is 8. You could possibly try to recompile it replacing the various places where this is defined with a "1", similar to what I did here when going down from 64 to 8.

    On the other hand, you could settle for 8kHz/8samples per blocks and effectively obtain 1kHz if you appropriately do downsampling at the beginning and upsampling at the end of render(). You could also think of plugging into core/PRU.cpp and replaced the routine that converts int to float and back to int so that it incorporates the filter and so you can save a few extra CPU cycles.

    thank you very much, I think I'll go fot the 8 khz SR, 8 Blocksize. One thing I couldn't really figure out right now is after I change the corecode in i2c_Codec.cpp is the context->audioSamplerate updated? I can't even figure out where this value gets set in the first place.

    The sampling rate is currently hard-coded into the context in RTAudio.cpp:

    186     gContext.audioSampleRate = 44100.0;

    I guess you will want to change that as well, as part of your changes to the core.

    I tried that now, everything compiles well and cpu usage drops as expected but i can't get audio out from the pd hello world patch after my changes to the core code that are as follows:
    i2c_Codec.cpp

    if(setPllP(3)) // <---3 instead of 8
    return 1;
    if(setPllR(2)) // <---2 instead of 1
    return 1;
    if(setAudioSamplingRate(8000)) // 8000 instead of 44100

    which gives me a k of 2.048 and the sample rate should be exactly 8000, these P, R and K values are all supported and reasonable are they?
    however getAudioSamplingRate() gives me 8000.000488 instead of the 8000 I would expect, so the k resolution might not be 0.0001 as stated int he comments?

    apart from that I only changed gContext.audioSampleRate = 44100.0; to gContext.audioSampleRate = 8000.0; and gContext.audioSampleRate = 8000.000488; both leading to no audio output from pd.

    any ideas?

    changing the register to 0xAA (setting fs to f_{S(ref)}/6) and setting up 48kHz with P = 1 R =1 gives me audio out with gContext.audioSampleRate = 8000.0 but getAudioSamplingRate() returns 48000.003906 so i think i'm doing something wrong with my PLL calculations :/
    CPU usage dropped from 20+ to 5 with my first attempt now it just drops to 10 with the hello world example.

    if(writeRegister(0x02, 0xAA))

    if(setPllP(1))
    	return 1;
    if(setPllR(1))
    	return 1;
    if(setAudioSamplingRate(48000)) //hack 8000Hz !!! was 44100 previously, this will automatically find and set K for the given P and R so that Fs=44100
    	return 1;

    I think it is not as easy as changing P, R and K.

    See e.g.: 10.3.3 and Table 8. Page 0/Register 2: Codec Sample Rate Select Register :
    it looks like you need to set fs = fs(ref)/NCODEC, with NCODEC = 6 and fs(ref) = 48kHz.

    This is done by:

    • setting NADC =NDAC = 6 in page 0/register 2.
    • you need to set fs(ref) to 48kHz in Page0/register7
    • then set the Pll values accordingly.

    This seems to do something reasonable for me, here's the patch

    diff --git a/core/I2c_Codec.cpp b/core/I2c_Codec.cpp
    index aaa754e..5a97df3 100644
    --- a/core/I2c_Codec.cpp
    +++ b/core/I2c_Codec.cpp
    @@ -41,7 +41,7 @@ int I2c_Codec::initCodec()
     int I2c_Codec::startAudio(int dual_rate)
     {
            // see datasehet for TLV320AIC3104 from page 44
    -       if(writeRegister(0x02, 0x00))   // Codec sample rate register: fs_ref / 1
    +       if(writeRegister(0x02, 0xAA))   // Codec sample rate register: fs_ref / 6
                    return 1;
            //      The sampling frequency is given as f_{S(ref)} = (PLLCLK_IN × K × R)/(2048 × P)
            // The master clock PLLCLK_IN is 12MHz
    @@ -49,18 +49,18 @@ int I2c_Codec::startAudio(int dual_rate)
            // using P=8 and R=1 gives a resolution of 0.0732421875Hz ( 0.000166% at 44.1kHz)
            // to obtain Fs=44100 we need to have K=60.2112
    
    -       if(setPllP(8))
    +       if(setPllP(3))
                    return 1;
    -       if(setPllR(1))
    +       if(setPllR(2))
                    return 1;
    -       if(setAudioSamplingRate(44100)) //this will automatically find and set K for the given P and R so that Fs=44100
    +       if(setAudioSamplingRate(8000)) //this will automatically find and set K for the given P and R so that Fs=44100
                    return 1;
            if(dual_rate) {
                    if(writeRegister(0x07, 0xEA))   // Codec datapath register: 44.1kHz; dual rate; standard datapath
                            return 1;
            }
            else {
    -               if(writeRegister(0x07, 0x8A))   // Codec datapath register: 44.1kHz; std rate; standard datapath
    +               if(writeRegister(0x07, 0x0A))   // Codec datapath register: fs(ref) = 48kHz; std rate; standard datapath
                            return 1;
            }

    EDIT: corrected the code to avoid leaving wrong code around.

    Actually this surely produces a slower sampling rate than 44.1kHz, but I don't think it is actually 8kHz. So maybe it requires some further work.

    I think if(writeRegister(0x02, 0x55)) should be if(writeRegister(0x02, 0xAA)) for f_{S(ref)}/6 .

    Very well done ! I had my bit reversed, despite double checking twice.
    Don't worry about the values returned by getAudioSamplingRate(), there is probably some difference in how the float division is handled in my code vs the PLL. You can check your P, L, J, D values against Table 1. Typical MCLK Rates in the datasheet.

    Regarding CPU usage, there is some overhead there due to converting ints to floats and back to ints in PRU.cpp. If you disable analog and digital channels, the CPU usage when idle should drop substantially.
    Also, Pd in general and its implementation of [osc~] are not very efficient.

    This is the final patch to get 8kHz sampling rate:

    diff --git a/core/I2c_Codec.cpp b/core/I2c_Codec.cpp
    index aaa754e..b1af4ae 100644
    --- a/core/I2c_Codec.cpp
    +++ b/core/I2c_Codec.cpp
    @@ -41,7 +41,7 @@ int I2c_Codec::initCodec()
     int I2c_Codec::startAudio(int dual_rate)
     {
     	// see datasehet for TLV320AIC3104 from page 44
    -	if(writeRegister(0x02, 0x00))	// Codec sample rate register: fs_ref / 1
    +	if(writeRegister(0x02, 0xAA))	// Codec sample rate register: fs_ref / 6
     		return 1;
     	//	The sampling frequency is given as f_{S(ref)} = (PLLCLK_IN × K × R)/(2048 × P)
     	// The master clock PLLCLK_IN is 12MHz
    @@ -49,18 +49,18 @@ int I2c_Codec::startAudio(int dual_rate)
     	// using P=8 and R=1 gives a resolution of 0.0732421875Hz ( 0.000166% at 44.1kHz)
     	// to obtain Fs=44100 we need to have K=60.2112
    
    -	if(setPllP(8))
    +	if(setPllP(1))
     		return 1;
     	if(setPllR(1))
     		return 1;
    -	if(setAudioSamplingRate(44100)) //this will automatically find and set K for the given P and R so that Fs=44100
    +	if(setAudioSamplingRate(48000)) //this will automatically find and set K for the given P and R so that Fs=48000
     		return 1;
     	if(dual_rate) {
     		if(writeRegister(0x07, 0xEA))	// Codec datapath register: 44.1kHz; dual rate; standard datapath
     			return 1;
     	}
     	else {
    -		if(writeRegister(0x07, 0x8A))	// Codec datapath register: 44.1kHz; std rate; standard datapath
    +		if(writeRegister(0x07, 0x0A))	// Codec datapath register: 48kHz; std rate; standard datapath
     			return 1;
     	}
     	if(writeRegister(0x08, 0xC0))	// Audio serial control register A: BLCK, WCLK outputs
    diff --git a/core/RTAudio.cpp b/core/RTAudio.cpp
    index 5e972c8..a7b5675 100644
    --- a/core/RTAudio.cpp
    +++ b/core/RTAudio.cpp
    @@ -183,7 +183,7 @@ int Bela_initAudio(BelaInitSettings *settings, void *userData)
     	}
    
     	// Initialise the rendering environment: sample rates, frame counts, numbers of channels
    -	gContext.audioSampleRate = 44100.0;
    +	gContext.audioSampleRate = 8000.0;

    well that seemed to work for a minute, then I decided to check cpu usage when turning off analog and digital inputs over the ide settings when running the hello world patch with analog in turned off there is no problem but with digital in turned off i get a

    Segmentation fault
    make: *** [runide] Error 139

    I just wanted to say that I'm very impressed with both the quantity an quality of the support I get here. I almost feel bad for utilising your time, are you employed for support purposes?

    UPDATE: SOLVED

    needed to comment out the following in default_libpd_render.c that should maybe belong inside a if(digital_enabled) ?

    	dcm.processInput(&context->digital[audioFrameBase], gLibpdBlockSize);
    
    // digital in at signal-rate
    	for (j = 0, p0 = gInBuf; j < gLibpdBlockSize; j++, p0++) {
    		unsigned int digitalFrame = audioFrameBase + j;
    		for (k = 0, p1 = p0 + gLibpdBlockSize * gFirstDigitalChannel;
    				k < 16; ++k, p1 += gLibpdBlockSize) {
    			if(dcm.isSignalRate(k) && dcm.isInput(k)){ // only process input channels that are handled at signal rate
    				*p1 = digitalRead(context, digitalFrame, k);
    			}
    		}
    	}

    and

    	for (j = 0, p0 = gOutBuf; j < gLibpdBlockSize; ++j, ++p0) {
    		unsigned int digitalFrame = (audioFrameBase + j);
    		for (k = 0, p1 = p0  + gLibpdBlockSize * gFirstDigitalChannel;
    				k < context->digitalChannels; k++, p1 += gLibpdBlockSize) {
    			if(dcm.isSignalRate(k) && dcm.isOutput(k)){ // only process output channels that are handled at signal rate
    				digitalWriteOnce(context, digitalFrame, k, *p1 > 0.5);
    			}
    		}
    	}
    
    	// digital out at message-rate
    	dcm.processOutput(&context->digital[audioFrameBase], gLibpdBlockSize);

    This gets me down to approx. 8 % CPU usage on the hello world sketch. Now I'm going to look into how much processing is possible on the plattform. My goal is to run a 2048 Tap FIR Filter and a LMS algorithm updating the coefficients furthermore a sigmund~ object should simultaneously analyze slices of 4096 Samples or more. How are your estimations, will horsepower suffice for that task?
    I have got this running on a Macbook Pro late 2013 with an i5 with puredatas DSP object reporting CPU usage at 20%.
    Am I too much of a dreamer to get that running on a beagle bone?
    There are a few things to to to get the sketch running on bela because of the LMS objects that need recompiling etc. and I could use some hope to run into the effort.

    8% seems about right. From my notes, these are example CPU usages for [sigmund~].

    [sigmund~ -npts 4096 -hop 4096 pitch env]
    uses about 26% of CPU.
    [sigmund~ -npts 4096 -hop 2048 pitch env]
    goes up to about 50%.

    Are you going to implement the FIR all in the time domain?
    Perhaps a partitioned convolution approach ( see William G. Gardner "Efficient Convolution without Input/Output Delay" ) mixing time-domain and frequency-domain would be more efficient, but no way you can do that entirely in Puredata.

    I assume the example CPU usages are at 44100 Hz Samplerate, effectively analysing chuncks of 4096 Samples every 4096/44100 and 2048/44100 seconds ?

    The FIR implementation I used until now is the one from iemlib that will need recompiling as well I'm not even sure how they implemented it but on my macbook I didn't even bother to think about it because CPU usage was never really a problem there.
    But if, and I'm currently relatively sure that will be the case, processing power will not yet suffice I will look into the approach you suggested.

    a month later

    @giuliomoro : I'm getting a roundtrip latency of 75 samples with the 8kHz Samplingrate, where I shoud get 16 (8 from output and 8 from Input Buffers) Samples or so. Do you have any explanation for the extra 59 Samples? May these be caused by the anti-alliasing filters?

    I'm generating a Noise in Puredata that ist looped with a patchcable to the input. The Latency is measured by identification of the Transferfunction via least mean square algorithm, that should be working right.

    Update: I just tested 44100 Hz Samplerate and get 28 Samples Roundtrip. I have that feeling that I'm missing something essential. Has it something to do with the way the codec is working?

    The sigma-delta converter has its own built-in filter 17 samples long in the ADC and 21 samples long in the DAC (see "group delay" in the codec datasheet). Some more info here.