Documentation on data types and conversions for int32buffer, frac32, frac32.s.map.ratio,


#1

Hi,

I am looking for some more information on the data types and conversions used when creating objects.

I have found some information in the user guide: in the "creating axo objects" part. Somewhere it was mentioned that -0x08000000 to 0x7FFFFFF (-2^27 to 2^27-1) are used to represent -64.0 to 64.0 as frac32. Is this correct?

More concretely I have a problem when multiplying a window with a sample value. It would be helpful if someone could explain exactly what is happening in gain.axo:

outlet_out= __SSAT(___SMMUL(param_amp,__SSAT(inlet_in,28)<<4)<<1,28);

Even the basics are not clear to me: how are audio samples exactly encoded? It uses a int32buffer but how does this translate to hex? To put it in other words how can you convert an audio sample, encoded as a float (-1.0 to 1.0) to the correct (int16_t, int32_t) value?

Another mystery to me is how echo.axo is using a delay line defined as:

int16_t delayline[attr_delaylength];

Are the sample values not encodes as 32 bit integers (as the int32buffer seems to suggest) ?

Another issue is the definition of parameters like frac32.s.map.ratio. Are these all converted to a -2^27 to 2^27-1 range and is the distinction only for display purposes?

In short it would be helpful if there were a more detailed user guide detailing the exact formats used, which would make it more easy to port algorithms to objects. Especially for people like me with some c/c++ experience but not much low level bit-banging ARM optimization knowledge.


#2

ah, this is an area Ive grappled with a few times, each time thinking I must write it down, and then not getting around to it.

so I'll give what I can remember from last time I looked, as a discussion point, it may be slightly inaccurate, but hopefully will get the ball rolling

k-rate - integer : straight encoding
k-rate - string : need to check i guess 8 bit char
k-rate - fraction (bi and unipolar) 1<< 21, so +/-64 = 6 bits, so 4/5 bits headroom (sign bit 31)

audio : 1 << 27 so really +/- ~ 15.0 , so 4 bits 'headroom' (sign bit 31)

(with the k-rate fractions there are then various 'interpretations' e.g. linear frequency , pitch, phase)

the tricky bit, and Im only just now getting the feel for it.... is then shifting things into the right ranges, and often combining left and right shifts e.g. (a << 7 ) >> 2) = a << 5, but with much less change of overflow.

audio encoding, there is no -1/+1 thats just a display representation, the DAC is using signed 32 integer encoding.

int16_t delayline - less precision, but longer delay line. convert by shifting appropriate number of bits.

when I come back to this , I just break out the disp/hex and start attaching dials, or looking at various 'simple' objects, though this time around Ive started creating some print objects in the community library, which I planned to have the various encodings for...
(e.g. there are certain conventions used for encoding pitch, frequencies etc)

of course, I agree a detailed user guide is a great idea. if you are exploring this, why not write it up and share as you go along, as we start to get more users coding objects , it will become increasingly important and useful resource.


#3

I totally agree with this. I also have some basic knowledge of C/C++, but I have a hard time figuring out what most code does. API documentation with all available functions and a short piece of code on how to use these functions would be really handy as well.


#4

Thanks. This is already very helpful to get me started. I will try to gain some more insight into the conversions and will share those here. Thanks again.


#5

I have made some objects that do simple operations on audio buffers. The first is a mix object that converts audio, mixes it and converts it again. The code is optimized for readability not for performance.

  // Capture the first input, it is encoded as a signed 
  // 32bit integer of which 27 bits are used. 
  // so to convert it to an interval [-1.0f , 1.0f] 
  // the following can be done:
  float input_one = (inlet_in1 / (float) (1<<27));
  // same for the second input which arrives at inlet_in2
  // note that the code generator automatically provides the 
  // array indexing. The line below is automatically converted to
  // float input_two = (inlet_in2[buffer_index] / (float) (1<<27));
  float input_two = (inlet_in2 / (float) (1<<27));

  // mixing is simply taking the sum of the two signals
  float mixed = input_one + input_two;
   
  // The following transforms the [-1.0f ; 1.0f] interval
  // to the axoloti convention interval of [-(1<<27) ; (1<<27)-1]
  outlet_out = (int32_t) (mixed * (1<<27));

Another object does a gain. It shows how to capture input from a dial:

  // frac32.u.map.gain is apparently mapped from 0 to 2^31
  // so the following gives a float between 0 and one
  float amplification = (param_amp / (float) (1<<31));

  // the value is simply multiplied with the current value of the
  // sample to get a correctly scaled output
  outlet_out = (int32_t) (amplification * inlet_in);

simple_gain.axo (987 Bytes)
simple_mix.axo (1.5 KB)

Please note that the comments might be not entirely correct. It reflects my current understanding of what is happening, but the objects seems to react as expected. A patch that uses these can be found here simpelton.axp (3.5 KB) .


#6

but why go via floats, this is inefficient, I think its better to 'get comfortable' with the necessary bit shifting, or at least this is generally the approach I'm taking.

kind of the idea i have, is only to use FP when interfacing between axoloti objects and 'external code/libraries' which have already been written using floats, this has the nice side effect of leaving the FPU available for this code, and not getting used by more mundane axoloti stuff, which can be just bit shifted around :smile:
(of course others may have different ideas/plans)


#7

I have created those objects as a kind of sanity check and with the aim of getting comfortable with the Axoloti conventions. The problem being that I need some kind of entry point to start understanding the bit shifting conventions (for which you kindly provided some insights earlier). The rationale being: if I am able to convert to float an back to fixed point int then I am reasonably sure that I understand what is going on.

Perhaps the objects can provide some insights to others as well which is why I posted them here.


#8

Perhaps I bit off more than I can chew but somehow I managed to get some sound out of an autotune patch I'm working on. It consists of two objects a pitch detector (yin) and a granular synthesis object called granulator. The pitch of an input is detected (currently an oscillator) by the pitch detector and via a midi keyboard the patch is able to determine how much the input pitch needs to be shifted to have the same frequency as the pressed midi key. The granulator subsequently shifts the pitch of the input to the requested pitch. That is the aim anyhow. As mentioned earlier I'm still struggling with the correct input/outputs.

Anyhow, the current alpha versions of the objects are included here for future reference and/or if someone wants to improve them.crappy_autotune.axp (3.6 KB)yin.axo (10.9 KB)
granulator.axo (6.8 KB)

Currently, the delaylength for the granulator is expressed in powers of two so a buffer size of 11 means 2^11. Only the pitchr (reference) and pitchd (detected) inputs are working at the moment. To pitch shift something it needs two different pitches and a ratio is determined automatically. Time stretching also kind of works but due to the small buffer and due to being unable to predict the future it is limited. I have tried to use sdram for the delay line but failed: the sdram version worked with an oscillator but not when reading a file from an sd card. How to initialize and use sdram is also an area that could use a bit more documentation (atrr_poly? parent->poly?).


#9

This sounds great! Looking forward to hearing it in action soon!

a|x


#10

Is the principle similar to this now-discontinued module?
http://www.gotharman.dk/Pitchshaper.htm

I've been intrigued by this module for a while, but hate the panel design. Would be great to have something similar for my Euxoloti module.

a|x


#11

philoop says :slight_smile: tb move this to axobject coding else do nothing