simd.h
SIMD.
#include <sonore/simd.h>- 1type
- 10other declarations
- Guides: Getting started, MIDI and MPE
On this page
Design notes
One type, Vec4f: four floats processed together. 128-bit / 4-wide is the common denominator of every target we ship to: SSE2 on x86-64, NEON on Apple Silicon and ARM Windows, and simd128 in WebAssembly. Picking the widest available instead (AVX, AVX-512) would mean a different vector width per platform, and the browser preview would stop matching the shipped plugin in the one dimension this SDK exists to keep identical.
WebAssembly matters here as much as native: the same DSP runs in the studio preview, and a toolkit that is only fast natively makes the preview the slow path for no reason. emscripten needs -msimd128; without it this header falls back to scalar and everything still works.
The scalar fallback is not a stub. It is compiled whenever no vector unit is available, and SONORE_NO_SIMD=1 selects it deliberately, which is how the tests prove the vector paths produce the SAME NUMBERS as the plain ones. A SIMD layer that changes the sound is a bug, not an optimisation.
Types 1
Four floats, one operation.
Deliberately a small, boring surface: load, store, arithmetic, min/max, and a horizontal sum. Everything the toolkit needs is expressible in those, and a bigger surface would be more per-platform code to get subtly wrong.
Functions 8
- fn
inline const char* backend()What actually got compiled, for a test or a log to state rather than guess.simd::backend · simd.h:50 - fn
inline constexpr bool vectorised()True when a vector unit (SSE2, NEON or wasm simd128) was compiled in, false on the scalar fallback. constexpr, sosimd::vectorised · simd.h:64if constexprcan branch on it. - fn
inline float dot(const float* a, const float* b, size_t n)dot(a, b) oversimd::dot · simd.h:311nfloats. The oversampler's FIR taps and the convolution partitions both reduce to this. - fn
inline void multiplyAccumulate(float* out, const float* a, const float* b, size_t n)out[i] += a[i] * b[i]: a fused multiply-accumulate over a whole block.simd::multiplyAccumulate · simd.h:321 - fn
inline void scale(float* out, const float* a, float scalar, size_t n)out[i] = a[i] * scalar.simd::scale · simd.h:329 - fn
inline void applyGain(float* data, float gain, size_t n)In-place gain over a block.simd::applyGain · simd.h:337 - fn
inline float peakAbs(const float* data, size_t n)The largest |sample| in a block: what a peak meter needs.simd::peakAbs · simd.h:340 - fn
inline double sumSquares(const float* data, size_t n)Sum of squares, for an RMS meter.simd::sumSquares · simd.h:357
Macros 2
- macro
#define SONORE_SIMD_NEON 1MSVC on Windows on Arm defines _M_ARM64 and NOT the ACLE __ARM_NEON, so without that last test cl.exe fell through to the scalar path: correct, identical numbers, and every block helper running at a quarter of its speed on exactly the machines that ship NEON in the base architecture.simd.h:36 - macro
#define SONORE_SIMD_SSE 1MSVC never defines __SSE2__; on x86-64 SSE2 is guaranteed by the ABI.simd.h:40