Hi,
On 19/12/2019 20:01, IOhannes m zmölnig wrote:
the high-performance phase-wrapping algorithm
For reference:
https://github.com/pure-data/pure-data/blob/e3a78da5b7d825bf8b9f5d313e4ea55e5e32e8f1/src/d_osc.c#L91-L97
(current master at time of writing)
Using a [phasor~] with x -= floor(x); for wrapping is about twice as
slow as the built-in tabfudge version, provided I compile with
-march=native on my AMD Ryzen 7 2700X Eight-Core Processor. When
compiled with pd-lib-builder's default -march=core2, the floor version
is over five times slower. I can run tests on other hardware in early
January if more data points are desired.
Benchmark methodology: time how long running 1000 copies of [phasor~
440] takes in pd -batch, with a timeout.pd that quits pd after 1 minute
of logical time. The tabfudge version finishes in 3 seconds. I used
the /usr/bin/pd in 0.49.0-3 (Debian Buster).
I suppose it's not so hard to load a custom phasor~ library (source
attached), if you need the extra accuracy of the floor version, and can
live with the slowdown. I did this already in one project for a vcf~
with internal double precision feedback state.
Claude
--
https://mathr.co.uk
PDLIBBUILDER_DIR=../pd-lib-builder/
lib.name = phasor~
class.sources = phasor~.c
include $(PDLIBBUILDER_DIR)/Makefile.pdlibbuilder
#include <m_pd.h>
#include <math.h>
/* -------------------------- phasor~ ------------------------------ */
static t_class *phasor_class;
typedef struct _phasor
{
t_object x_obj;
double x_phase;
float x_conv;
float x_f; /* scalar frequency */
} t_phasor;
static void *phasor_new(t_floatarg f)
{
t_phasor *x = (t_phasor *)pd_new(phasor_class);
x->x_f = f;
inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("ft1"));
x->x_phase = 0;
x->x_conv = 0;
outlet_new(&x->x_obj, gensym("signal"));
return (x);
}
static t_int *phasor_perform(t_int *w)
{
t_phasor *x = (t_phasor *)(w[1]);
t_float *in = (t_float *)(w[2]);
t_float *out = (t_float *)(w[3]);
int n = (int)(w[4]);
double dphase = x->x_phase;
float conv = x->x_conv;
while (n--)
{
dphase += *in++ * conv;
dphase -= floor(dphase);
*out++ = dphase;
}
x->x_phase = dphase;
return (w+5);
}
static void phasor_dsp(t_phasor *x, t_signal **sp)
{
x->x_conv = 1./sp[0]->s_sr;
dsp_add(phasor_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
}
static void phasor_ft1(t_phasor *x, t_float f)
{
x->x_phase = f;
}
extern void phasor_tilde_setup(void)
{
phasor_class = class_new(gensym("phasor~"), (t_newmethod)phasor_new, 0,
sizeof(t_phasor), 0, A_DEFFLOAT, 0);
CLASS_MAINSIGNALIN(phasor_class, t_phasor, x_f);
class_addmethod(phasor_class, (t_method)phasor_dsp,
gensym("dsp"), A_CANT, 0);
class_addmethod(phasor_class, (t_method)phasor_ft1,
gensym("ft1"), A_FLOAT, 0);
}
_______________________________________________
Pd-dev mailing list
[email protected]
https://lists.puredata.info/listinfo/pd-dev