File f32_to_i32_core.h¶
FileList > doppler > f32_to_i32 > f32_to_i32_core.h
Go to the source code of this file
Scale-and-saturate float-to-int32 converter. More...
#include "doppler/clib_common.h"#include "doppler/dp_state.h"#include "doppler/jm_perf.h"#include <math.h>
Classes¶
| Type | Name |
|---|---|
| struct | dp_f32_to_i32_state_t F32ToI32 state. |
Public Functions¶
| Type | Name |
|---|---|
| dp_f32_to_i32_state_t * | dp_f32_to_i32_create (float scale) Create a f32_to_i32 instance. |
| void | dp_f32_to_i32_destroy (dp_f32_to_i32_state_t * state) Destroy a f32_to_i32 instance and release all memory. |
| void | dp_f32_to_i32_get_state (const dp_f32_to_i32_state_t * state, void * blob) |
| void | dp_f32_to_i32_reset (dp_f32_to_i32_state_t * state) Clear the sticky clip flag, starting a fresh saturation history. |
| int | dp_f32_to_i32_set_state (dp_f32_to_i32_state_t * state, const void * blob) |
| size_t | dp_f32_to_i32_state_bytes (const dp_f32_to_i32_state_t * state) |
| JM_FORCEINLINE JM_HOT int32_t | dp_f32_to_i32_step (dp_f32_to_i32_state_t * state, float x) Scale one float sample by scale , round, and saturate to int32. |
| void | dp_f32_to_i32_steps (dp_f32_to_i32_state_t * state, const float * input, int32_t * output, size_t n) Process a block of float samples to int32. |
Macros¶
| Type | Name |
|---|---|
| define | F32_TO_I32_STATE_MAGIC [**DP\_FOURCC**](dp__state_8h.md#define-dp_fourcc) ('F','2','3','2') |
| define | F32_TO_I32_STATE_VERSION 1u |
Detailed Description¶
Multiplies the input by scale, rounds to the nearest integer, and saturates (clamps) the result to the int32 range [-2147483648, 2147483647]. The default scale of 2147483648.0 (2^31) maps a normalised [-1, +1] float to the full 32-bit integer range, making it the exact counterpart of I32ToF32. A sticky clipped flag is raised on any sample that saturates and is cleared only by reset().
The full scale is 2^31, not 2^31-1: the code grid a converter actually has is 2^32 equally spaced steps of 1/2^31, so scaling by 2^31 maps the normalised range onto that grid exactly and a dyadic input round-trips with no error. An input of exactly +1.0 lands on 2^31, one past INT32_MAX by construction, and saturating it is what this mapping means rather than a failure of it.
Note the source is a float32, so only 24 significant bits survive the multiply — the low bits of a full-scale code are not meaningful, and two inputs a float apart can produce codes hundreds apart. That is a property of the input type, not of this conversion; I32ToF32 documents the mirror.
Lifecycle: create -> (step / steps / reset)* -> destroy
>>> from doppler.cvt import F32ToI32
>>> import numpy as np
>>> obj = F32ToI32(scale=2147483648.0)
>>> obj.step(0.5)
1073741824
>>> obj.step(-1.0)
-2147483648
>>> obj.clipped
False
>>> obj.step(1.0)
2147483647
>>> obj.clipped
True
>>> obj.reset()
>>> obj.clipped
False
>>> x = np.array([0.0, 0.25, -0.5], dtype=np.float32)
>>> obj.steps(x).tolist()
[0, 536870912, -1073741824]
Public Functions Documentation¶
function dp_f32_to_i32_create¶
Create a f32_to_i32 instance.
Allocates state and stores scale. The clipped flag is initialised to 0. Returns NULL for a non-positive scale, which is the only failure a caller can cause; the allocation itself aborts on exhaustion (dp_xcalloc) rather than handing back an unwind path no test can reach.
Parameters:
scaleMultiply factor applied before rounding and saturation (default: 2147483648.0f). Use 2^31 to convert a normalised[-1, +1]signal to the full 32-bit range.
Returns:
Heap-allocated state, or NULL if scale is not positive.
Note:
Caller must call dp_f32_to_i32_destroy() when done.
function dp_f32_to_i32_destroy¶
Destroy a f32_to_i32 instance and release all memory.
Parameters:
stateMay be NULL.
function dp_f32_to_i32_get_state¶
function dp_f32_to_i32_reset¶
Clear the sticky clip flag, starting a fresh saturation history.
Zeroes clipped so a subsequent clipped query reflects only samples seen after this call; the immutable scale is preserved. Call it at a buffer or segment boundary so a saturation on one block does not leak into the next.
Parameters:
stateMust be non-NULL.
>>> from doppler.cvt import F32ToI32
>>> c = F32ToI32()
>>> c.step(9.0) # out of range -> saturates, latches clipped
2147483647
>>> c.reset() # forget the clip history
>>> c.clipped
False
function dp_f32_to_i32_set_state¶
function dp_f32_to_i32_state_bytes¶
function dp_f32_to_i32_step¶
Scale one float sample by scale , round, and saturate to int32.
Computes round(x * scale), clamps to the int32 range [-2147483648, 2147483647], and latches the sticky clipped flag if the scaled value fell outside that range before clamping. At the default scale of 2^31 a normalised [-1, +1] input maps to the full 32-bit code range.
Unlike its int8 and int16 siblings this works in double throughout. INT32_MAX is not representable as a float — 2147483647.0f rounds UP to 2^31 — so a float fminf(s, 2147483647.0f) clamps to a value one past the range it is trying to enforce, and the following lround() overflows. The float32 input still bounds the useful precision at 24 bits; the double is there to make the CLAMP exact, not to invent significance.
Parameters:
stateMust be non-NULL.xInput sample, normally a normalised float in[-1, +1].
Returns:
Saturated int32 code in [-2147483648, 2147483647].
>>> from doppler.cvt import F32ToI32
>>> c = F32ToI32(scale=2147483648.0) # normalised float -> full-scale
>>> c.step(0.5) # 0.5 * 2**31
1073741824
>>> c.step(2.0) # beyond +1.0 -> saturates to max
2147483647
>>> c.clipped # sticky flag latched by the clip
True
function dp_f32_to_i32_steps¶
Process a block of float samples to int32.
void dp_f32_to_i32_steps (
dp_f32_to_i32_state_t * state,
const float * input,
int32_t * output,
size_t n
)
Applies step() to every element. The clipped flag is updated cumulatively across the block — a single saturating sample raises it for the entire call. Accepts an optional pre-allocated output array; allocates a fresh one when output is NULL.
Parameters:
stateMust be non-NULL.inputInput float32 array; must contain at leastnelements.outputOutput int32 array; must contain at leastnelements.nNumber of samples to process.
>>> from doppler.cvt import F32ToI32
>>> import numpy as np
>>> x = np.array([0.0, 0.25, -1.0], dtype=np.float32)
>>> F32ToI32().steps(x).tolist() # scale=2**31 -> full-scale int32
[0, 536870912, -2147483648]
Macro Definition Documentation¶
define F32_TO_I32_STATE_MAGIC¶
define F32_TO_I32_STATE_VERSION¶
The documentation for this class was generated from the following file native/inc/doppler/f32_to_i32/f32_to_i32_core.h