Scenario 1 — Simple standalone extension¶
You're here if: you have one algorithm to wrap — a filter, a running
statistic, an oscillator — and you want it available as from my_dsp import Engine with full C and Python tests.
A single C object exposed as a Python extension. Good starting point for wrapping an algorithm, DSP primitive, or performance-critical inner loop.
1. Scaffold¶
just-makeit new my_dsp \
--object gain \
--arg-type float \
--return-type float \
--state gain:float:1.0
cd my_dsp
--arg-type and --return-type set the C types for step()'s input and
output. Omit both and they default to float _Complex.
2. Implement¶
Open native/inc/gain/gain_core.h and fill in the gain_step stub:
gain_steps() — the block processor — is already in gain_core.c and loops
over this automatically. You do not edit the Python binding (gain_ext.c).
3. Build and test¶
4. Install¶
Note: Run inside an activated virtual environment. Use
jm-install-deps path/to/venv && source path/to/venv/bin/activateto create one with all build deps included.
python3 -m pip install . # build wheel + install
python3 -m pip install -e . # editable install (Python-only edits take effect immediately)
5. Use from Python¶
import numpy as np
from my_dsp import Gain
g = Gain(gain=2.0)
# single sample
y = g.step(1.0) # → 2.0
# block
x = np.ones(1024, dtype=np.float32)
y = g.steps(x) # → float32 ndarray, all 2.0
# getters / setters
g.set_gain(0.5)
g.get_gain() # → 0.5
# reset to declared defaults
g.reset()
# context manager
with Gain(gain=2.0) as g:
y = g.steps(x)
6. Optional: performance annotations¶
Once the algorithm is working and tested:
Patches step() with JM_FORCEINLINE JM_HOT, writes jm_perf.h and
jm_simd.h, and records the setting so future object and add calls
inherit it. See Performance annotations for the full reference.