File f32_to_i8_core.h¶
FileList > doppler > f32_to_i8 > f32_to_i8_core.h
Go to the source code of this file
Scale-and-saturate float-to-int8 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_i8_state_t F32ToI8 state. |
Public Functions¶
| Type | Name |
|---|---|
| dp_f32_to_i8_state_t * | dp_f32_to_i8_create (float scale) Create a f32_to_i8 instance. |
| void | dp_f32_to_i8_destroy (dp_f32_to_i8_state_t * state) Destroy a f32_to_i8 instance and release all memory. |
| void | dp_f32_to_i8_get_state (const dp_f32_to_i8_state_t * state, void * blob) |
| void | dp_f32_to_i8_reset (dp_f32_to_i8_state_t * state) Clear the sticky clip flag, starting a fresh saturation history. |
| int | dp_f32_to_i8_set_state (dp_f32_to_i8_state_t * state, const void * blob) |
| size_t | dp_f32_to_i8_state_bytes (const dp_f32_to_i8_state_t * state) |
| JM_FORCEINLINE JM_HOT int8_t | dp_f32_to_i8_step (dp_f32_to_i8_state_t * state, float x) Scale one float sample by scale , round, and saturate to int8. |
| void | dp_f32_to_i8_steps (dp_f32_to_i8_state_t * state, const float * input, int8_t * output, size_t n) Process a block of float samples to int8. |
Macros¶
| Type | Name |
|---|---|
| define | F32_TO_I8_STATE_MAGIC [**DP\_FOURCC**](dp__state_8h.md#define-dp_fourcc) ('F','2','\_','8') |
| define | F32_TO_I8_STATE_VERSION 1u |
Detailed Description¶
Multiplies the input by scale, rounds to the nearest integer, and saturates (clamps) the result to the int8 range [-128, 127]. The default scale of 128.0 maps a normalised [-1, +1] float to the full 8-bit integer range, making it the exact counterpart of I8ToF32. A sticky clipped flag is raised on any sample that saturates and is cleared only by reset().
The full scale is 2^7, not 127: the code grid a converter actually has is 2^8 equally spaced steps of 1/2^7, so scaling by 2^7 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 128, one past INT8_MAX by construction, and saturating it is what this mapping means rather than a failure of it.
Lifecycle: create -> (step / steps / reset)* -> destroy
>>> from doppler.cvt import F32ToI8
>>> import numpy as np
>>> obj = F32ToI8(scale=128.0)
>>> obj.step(0.5)
64
>>> obj.step(-1.0)
-128
>>> obj.clipped
False
>>> obj.step(1.0)
127
>>> obj.clipped
True
>>> obj.reset()
>>> obj.clipped
False
>>> x = np.array([0.5, -0.5, 1.0], dtype=np.float32)
>>> obj.steps(x).tolist()
[64, -64, 127]
Public Functions Documentation¶
function dp_f32_to_i8_create¶
Create a f32_to_i8 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: 128.0f). Use 128.0 to convert a normalised[-1, +1]signal to the full 8-bit range.
Returns:
Heap-allocated state, or NULL if scale is not positive.
Note:
Caller must call dp_f32_to_i8_destroy() when done.
function dp_f32_to_i8_destroy¶
Destroy a f32_to_i8 instance and release all memory.
Parameters:
stateMay be NULL.
function dp_f32_to_i8_get_state¶
function dp_f32_to_i8_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 F32ToI8
>>> c = F32ToI8()
>>> c.step(9.0) # out of range -> saturates, latches clipped
127
>>> c.reset() # forget the clip history
>>> c.clipped
False
function dp_f32_to_i8_set_state¶
function dp_f32_to_i8_state_bytes¶
function dp_f32_to_i8_step¶
Scale one float sample by scale , round, and saturate to int8.
Computes round(x * scale), clamps to the int8 range [-128, 127], and latches the sticky clipped flag if the scaled value fell outside that range before clamping. At the default scale of 128 a normalised [-1, +1] input maps to the full 8-bit code range.
Parameters:
stateMust be non-NULL.xInput sample, normally a normalised float in[-1, +1].
Returns:
Saturated int8 code in [-128, 127].
>>> from doppler.cvt import F32ToI8
>>> c = F32ToI8(scale=128.0) # normalised float -> full-scale int8
>>> c.step(0.5) # 0.5 * 128
64
>>> c.step(2.0) # beyond +1.0 -> saturates to max
127
>>> c.clipped # sticky flag latched by the clip
True
function dp_f32_to_i8_steps¶
Process a block of float samples to int8.
void dp_f32_to_i8_steps (
dp_f32_to_i8_state_t * state,
const float * input,
int8_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 int8 array; must contain at leastnelements.nNumber of samples to process.
>>> from doppler.cvt import F32ToI8
>>> import numpy as np
>>> x = np.array([0.0, 0.5, -1.0, 0.99], dtype=np.float32)
>>> F32ToI8().steps(x).tolist() # scale=128 -> full-scale int8
[0, 64, -128, 127]
Macro Definition Documentation¶
define F32_TO_I8_STATE_MAGIC¶
define F32_TO_I8_STATE_VERSION¶
The documentation for this class was generated from the following file native/inc/doppler/f32_to_i8/f32_to_i8_core.h