std1.0.0-beta-7 SafeC docs

Source dsp/resample.sc

View in the repository

// SafeC Standard Library — Resampling implementation (see resample.h)
#pragma once
#include <std/simd/cpu.h>
#include <std/simd/simd.h>
#include <std/sync/parallel.h>
#include <std/dsp/resample.h>
#include <std/dsp/fixed.h>
#include <std/math.h>

#define SAFEC_DSP_PI_RESAMPLE 3.14159265358979323846

namespace std {

// The shared core (resample_core.h) on double samples; resample_f32.sc
// builds it on float samples.
#define RS_T        double
#define RS_NEAREST  resample_nearest_n_
#define RS_LINEAR   resample_linear_n_
#define RS_SINC     resample_sinc_n_
#include <std/dsp/resample_core.h>

void fresample_nearest_n_(const &Fixed in, unsigned long inLen, &Fixed out, unsigned long outLen) {
    if (inLen == 0UL || outLen == 0UL) { return; }
    double scale = (double)inLen / (double)outLen;
    unsigned long i = 0UL;
    while (i < outLen) {
        double srcPos = (double)i * scale;
        unsigned long idx = (unsigned long)(srcPos + 0.5);
        if (idx >= inLen) { idx = inLen - 1UL; }
        Fixed v;
        unsafe {
            v = in[idx];
            out[i] = v;
        }
        i = i + 1UL;
    }
}

void fresample_linear_n_(const &Fixed in, unsigned long inLen, &Fixed out, unsigned long outLen) {
    if (inLen == 0UL || outLen == 0UL) { return; }
    if (inLen == 1UL) {
        Fixed v;
        unsafe { v = in[0]; }
        unsigned long i = 0UL;
        while (i < outLen) {
            unsafe { out[i] = v; }
            i = i + 1UL;
        }
        return;
    }
    double scale = 0.0;
    if (outLen > 1UL) {
        scale = (double)(inLen - 1UL) / (double)(outLen - 1UL);
    }
    unsigned long i = 0UL;
    while (i < outLen) {
        double srcPos = (double)i * scale;
        unsigned long idx0 = (unsigned long)srcPos;
        unsigned long idx1 = idx0 + 1UL;
        if (idx1 >= inLen) { idx1 = inLen - 1UL; }
        double frac = srcPos - (double)idx0;
        Fixed v0;
        Fixed v1;
        unsafe {
            v0 = in[idx0];
            v1 = in[idx1];
        }
        Fixed fracFixed = fixed_from_float(frac);
        Fixed diff = fixed_sub(v1, v0);
        Fixed interp = fixed_add(v0, fixed_mul(fracFixed, diff));
        unsafe { out[i] = interp; }
        i = i + 1UL;
    }
}

// ── Slice API (the public signatures; the (reference, length) cores above
// are the *_n_ functions) ─────────────────────────────────────────────────────

void resample_nearest([]const double in, []double out) {
    if (in.len == 0UL || out.len == 0UL) return;
    unsafe { resample_nearest_n_((const &double)in.ptr, in.len, (&double)out.ptr, out.len); }
}

void resample_linear([]const double in, []double out) {
    if (in.len == 0UL || out.len == 0UL) return;
    unsafe { resample_linear_n_((const &double)in.ptr, in.len, (&double)out.ptr, out.len); }
}

void resample_sinc([]const double in, []double out, unsigned long kernelHalfWidth) {
    if (in.len == 0UL || out.len == 0UL) return;
    unsafe { resample_sinc_n_((const &double)in.ptr, in.len, (&double)out.ptr, out.len, kernelHalfWidth); }
}

void fresample_nearest([]const Fixed in, []Fixed out) {
    if (in.len == 0UL || out.len == 0UL) return;
    unsafe { fresample_nearest_n_((const &Fixed)in.ptr, in.len, (&Fixed)out.ptr, out.len); }
}

void fresample_linear([]const Fixed in, []Fixed out) {
    if (in.len == 0UL || out.len == 0UL) return;
    unsafe { fresample_linear_n_((const &Fixed)in.ptr, in.len, (&Fixed)out.ptr, out.len); }
}

} // namespace std