How to make a `delay/read_interp` object that takes amount of samples as parameter?


#1

I'm trying to modify the delay/read_interp object so that it takes an amount of samples (or in other words amount of s-rate cycles) as parameter instead of the "kind of percentage" parameter it takes by default.
What I'd like to do is, say the delay/write is 256 samples and I'd like to use half of that is pass 128 into the time parameter.

This is the s-rate code from the delay/read_interp object:

uint32_t tmp_d =  __USAT(param_time + inlet_time,27);
uint32_t tmp_di = attr_delayname.writepos - (tmp_d>>(27-attr_delayname.LENGTHPOW)) - BUFSIZE + buffer_index -1;
uint32_t tmp_w1 = (tmp_d<<(attr_delayname.LENGTHPOW+3)) & 0x3FFFFFFF;
uint32_t tmp_w2 = (1<<30) - tmp_w1;
int32_t tmp_a1 = attr_delayname.array[tmp_di&attr_delayname.LENGTHMASK]<<16;
int32_t tmp_a2 = attr_delayname.array[(tmp_di+1)&attr_delayname.LENGTHMASK]<<16;
int32_t tmp_r = ___SMMUL(tmp_a1,tmp_w1);
tmp_r = ___SMMLA(tmp_a2,tmp_w2,tmp_r);
outlet_out= tmp_r;

I tried to make sense of it, but I have no clue why all the bitshifting is happening and where the (to me) "magic" values like 3, 0x3FFFFFFF and 30 come from.
Does anyone have an idea how to rewrite this so it takes samples/s-rate cycle count as input?


#2

@simonvanderveldt

You dont need to edit anything inside that object, to do what you want to do. You just need to scale whatever you send to time inlet. The specific example you give with 256 samples and then use 128 samples is pretty easy:
If you set the delay write delay time to the 256 samples and you want to set a delay time of 128 samples you can do it like this:

Beside that you can probably find some object that converts samples to krate values, so you can set the values with real numbers. I think Sir Sick Sik maybe has got one called sss/timers/Clock2Timing. Try it out. It actualle needs some trigger inputs and then it calculates the speed from the time between 2 triggers. But I think you can probably hack that object, bypass the trigger values and simply just type in the values in samples.

Sorry I cant give you a meaningful explanation for this, someone else with a deeper understanding of code have to give you that one, but YES... all the bitshifting also drove me nuts to start with. But I think it has to do with that Axoloti is a board with very limited resources and bitshifting values to a smaller scale saved memory, CPU etc.... But don't hang for this, I am just thinking out loud, hehe :slight_smile:

Regarding the bitshifting, I would advice you to use some of the display objects, so you can see what is actually going on when you bitshift.


#3

I tried to make sense of it, but I have no clue why all the bitshifting is happening and where the (to me) "magic" values like 3, 0x3FFFFFFF and 30 come from.

They're coming from the use of fixed point math (Q5.27 values in this case). The code for fixed point math is often efficient at the cost of being a bit "write-only".

tmp_di is the index into the array
tmp_a* are the values of the array.
tmp_w* are the relative weight of the di and di+1 sample. (scaled to 1 << 30)
The smmul/smmla is the actual LERP computation.


#4

@deadsy

Thanks for elaborating it.


#5

note: this is 'off the top of my head', so I might be missing something, as Ive not tested below, but hopefully gives you the general idea of what to try.

basically this is the line you want to change... because your using samples directly, basically (tmp_d>>(27-attr_delayname.LENGTHPOW)) is calculating number of samples.

however, given you are given a particular sample, rather than a time, you also don't need to 'interp' it, since you will always fall on a particular sample. this means you can ditch tmp_w1/w2 and tmp_a2.
(the shift 16 might also have to change, but id have to go check the code a bit more to know for sure)

note: the adding of LENGTHMASK is being used to keep the sample read in range, and also wrapping.