Newer
Older
/* Copyright (c) 1997- Miller Puckette and others.
* For information on usage and redistribution, and for a DISCLAIMER OF ALL
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
#include "m_pd.h"
/* This file interfaces to one of the Mayer, Ooura, or fftw FFT packages
to implement the "fft~", etc, Pd objects. If using Mayer, also compile
d_fft_mayer.c; if ooura, use d_fft_fftsg.c instead; if fftw, use d_fft_fftw.c
and also link in the fftw library. You can only have one of these three
linked in. The configure script can be used to select which one.
*/
/* ---------------- utility functions for DSP chains ---------------------- */
/* swap two arrays */
static t_int *sigfft_swap(t_int *w)
{
t_sample *in1 = (t_sample *)(w[1]);
t_sample *in2 = (t_sample *)(w[2]);
*in1 = *in2;
*in2 = f;
}
return (w+4);
}
/* take array1 (supply a pointer to beginning) and copy it,
into decreasing addresses, into array 2 (supply a pointer one past the
end), and negate the sign. */
static t_int *sigrfft_flip(t_int *w)
{
t_sample *in = (t_sample *)(w[1]);
t_sample *out = (t_sample *)(w[2]);
int n = w[3];
while (n--)
*(--out) = - *in++;
return (w+4);
}
/* ------------------------ fft~ and ifft~ -------------------------------- */
static t_class *sigfft_class, *sigifft_class;
typedef struct fft
{
t_object x_obj;
} t_sigfft;
static void *sigfft_new(void)
{
t_sigfft *x = (t_sigfft *)pd_new(sigfft_class);
outlet_new(&x->x_obj, gensym("signal"));
outlet_new(&x->x_obj, gensym("signal"));
inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
x->x_f = 0;
return (x);
}
static void *sigifft_new(void)
{
t_sigfft *x = (t_sigfft *)pd_new(sigifft_class);
outlet_new(&x->x_obj, gensym("signal"));
outlet_new(&x->x_obj, gensym("signal"));
inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
x->x_f = 0;
return (x);
}
static t_int *sigfft_perform(t_int *w)
{
t_sample *in1 = (t_sample *)(w[1]);
t_sample *in2 = (t_sample *)(w[2]);
int n = w[3];
mayer_fft(n, in1, in2);
return (w+4);
}
static t_int *sigifft_perform(t_int *w)
{
t_sample *in1 = (t_sample *)(w[1]);
t_sample *in2 = (t_sample *)(w[2]);
int n = w[3];
mayer_ifft(n, in1, in2);
return (w+4);
}
static void sigfft_dspx(t_sigfft *x, t_signal **sp, t_int *(*f)(t_int *w))
{
int n = sp[0]->s_n;
t_sample *in1 = sp[0]->s_vec;
t_sample *in2 = sp[1]->s_vec;
t_sample *out1 = sp[2]->s_vec;
t_sample *out2 = sp[3]->s_vec;
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
if (out1 == in2 && out2 == in1)
dsp_add(sigfft_swap, 3, out1, out2, n);
else if (out1 == in2)
{
dsp_add(copy_perform, 3, in2, out2, n);
dsp_add(copy_perform, 3, in1, out1, n);
}
else
{
if (out1 != in1) dsp_add(copy_perform, 3, in1, out1, n);
if (out2 != in2) dsp_add(copy_perform, 3, in2, out2, n);
}
dsp_add(f, 3, sp[2]->s_vec, sp[3]->s_vec, n);
}
static void sigfft_dsp(t_sigfft *x, t_signal **sp)
{
sigfft_dspx(x, sp, sigfft_perform);
}
static void sigifft_dsp(t_sigfft *x, t_signal **sp)
{
sigfft_dspx(x, sp, sigifft_perform);
}
static void sigfft_setup(void)
{
sigfft_class = class_new(gensym("fft~"), sigfft_new, 0,
sizeof(t_sigfft), 0, 0);
CLASS_MAINSIGNALIN(sigfft_class, t_sigfft, x_f);
class_addmethod(sigfft_class, (t_method)sigfft_dsp, gensym("dsp"),
A_CANT, 0);
sigifft_class = class_new(gensym("ifft~"), sigifft_new, 0,
sizeof(t_sigfft), 0, 0);
CLASS_MAINSIGNALIN(sigifft_class, t_sigfft, x_f);
class_addmethod(sigifft_class, (t_method)sigifft_dsp, gensym("dsp"),
A_CANT, 0);
class_sethelpsymbol(sigifft_class, gensym("fft~"));
}
/* ----------------------- rfft~ -------------------------------- */
static t_class *sigrfft_class;
typedef struct rfft
{
t_object x_obj;
} t_sigrfft;
static void *sigrfft_new(void)
{
t_sigrfft *x = (t_sigrfft *)pd_new(sigrfft_class);
outlet_new(&x->x_obj, gensym("signal"));
outlet_new(&x->x_obj, gensym("signal"));
x->x_f = 0;
return (x);
}
static t_int *sigrfft_perform(t_int *w)
{
t_sample *in = (t_sample *)(w[1]);
int n = w[2];
mayer_realfft(n, in);
return (w+3);
}
static void sigrfft_dsp(t_sigrfft *x, t_signal **sp)
{
int n = sp[0]->s_n, n2 = (n>>1);
t_sample *in1 = sp[0]->s_vec;
t_sample *out1 = sp[1]->s_vec;
t_sample *out2 = sp[2]->s_vec;
if (n < 4)
{
error("fft: minimum 4 points");
return;
}
if (in1 != out1)
dsp_add(copy_perform, 3, in1, out1, n);
dsp_add(sigrfft_perform, 2, out1, n);
dsp_add(sigrfft_flip, 3, out1 + (n2+1), out2 + n2, n2-1);
dsp_add_zero(out1 + (n2+1), ((n2-1)&(~7)));
dsp_add_zero(out1 + (n2+1) + ((n2-1)&(~7)), ((n2-1)&7));
dsp_add_zero(out2 + n2, n2);
dsp_add_zero(out2, 1);
}
static void sigrfft_setup(void)
{
sigrfft_class = class_new(gensym("rfft~"), sigrfft_new, 0,
sizeof(t_sigrfft), 0, 0);
CLASS_MAINSIGNALIN(sigrfft_class, t_sigrfft, x_f);
class_addmethod(sigrfft_class, (t_method)sigrfft_dsp, gensym("dsp"),
A_CANT, 0);
class_sethelpsymbol(sigrfft_class, gensym("fft~"));
}
/* ----------------------- rifft~ -------------------------------- */
static t_class *sigrifft_class;
typedef struct rifft
{
t_object x_obj;
} t_sigrifft;
static void *sigrifft_new(void)
{
t_sigrifft *x = (t_sigrifft *)pd_new(sigrifft_class);
inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
outlet_new(&x->x_obj, gensym("signal"));
x->x_f = 0;
return (x);
}
static t_int *sigrifft_perform(t_int *w)
{
t_sample *in = (t_sample *)(w[1]);
int n = w[2];
mayer_realifft(n, in);
return (w+3);
}
static void sigrifft_dsp(t_sigrifft *x, t_signal **sp)
{
int n = sp[0]->s_n, n2 = (n>>1);
t_sample *in1 = sp[0]->s_vec;
t_sample *in2 = sp[1]->s_vec;
t_sample *out1 = sp[2]->s_vec;
if (n < 4)
{
error("fft: minimum 4 points");
return;
}
if (in2 == out1)
{
dsp_add(sigrfft_flip, 3, out1+1, out1 + n, n2-1);
dsp_add(copy_perform, 3, in1, out1, n2+1);
}
else
{
if (in1 != out1) dsp_add(copy_perform, 3, in1, out1, n2+1);
dsp_add(sigrfft_flip, 3, in2+1, out1 + n, n2-1);
}
dsp_add(sigrifft_perform, 2, out1, n);
}
static void sigrifft_setup(void)
{
sigrifft_class = class_new(gensym("rifft~"), sigrifft_new, 0,
sizeof(t_sigrifft), 0, 0);
CLASS_MAINSIGNALIN(sigrifft_class, t_sigrifft, x_f);
class_addmethod(sigrifft_class, (t_method)sigrifft_dsp, gensym("dsp"),
A_CANT, 0);
class_sethelpsymbol(sigrifft_class, gensym("fft~"));
}
/* ----------------------- framp~ -------------------------------- */
static t_class *sigframp_class;
typedef struct framp
{
t_object x_obj;
} t_sigframp;
static void *sigframp_new(void)
{
t_sigframp *x = (t_sigframp *)pd_new(sigframp_class);
inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
outlet_new(&x->x_obj, gensym("signal"));
outlet_new(&x->x_obj, gensym("signal"));
x->x_f = 0;
return (x);
}
static t_int *sigframp_perform(t_int *w)
{
t_sample *inreal = (t_sample *)(w[1]);
t_sample *inimag = (t_sample *)(w[2]);
t_sample *outfreq = (t_sample *)(w[3]);
t_sample *outamp = (t_sample *)(w[4]);
t_sample lastreal = 0, currentreal = inreal[0], nextreal = inreal[1];
t_sample lastimag = 0, currentimag = inimag[0], nextimag = inimag[1];
t_sample fbin = 1, oneovern2 = 1.f/((t_sample)n * (t_sample)n);
inreal += 2;
inimag += 2;
*outamp++ = *outfreq++ = 0;
n -= 2;
while (n--)
{
t_sample re, im, pow, freq;
lastreal = currentreal;
currentreal = nextreal;
nextreal = *inreal++;
lastimag = currentimag;
currentimag = nextimag;
nextimag = *inimag++;
re = currentreal - 0.5f * (lastreal + nextreal);
im = currentimag - 0.5f * (lastimag + nextimag);
pow = re * re + im * im;
if (pow > 1e-19)
{
t_sample detune = ((lastreal - nextreal) * re +
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
(lastimag - nextimag) * im) / (2.0f * pow);
if (detune > 2 || detune < -2) freq = pow = 0;
else freq = fbin + detune;
}
else freq = pow = 0;
*outfreq++ = freq;
*outamp++ = oneovern2 * pow;
fbin += 1.0f;
}
while (m--) *outamp++ = *outfreq++ = 0;
return (w+6);
}
t_int *sigsqrt_perform(t_int *w);
static void sigframp_dsp(t_sigframp *x, t_signal **sp)
{
int n = sp[0]->s_n, n2 = (n>>1);
if (n < 4)
{
error("framp: minimum 4 points");
return;
}
dsp_add(sigframp_perform, 5, sp[0]->s_vec, sp[1]->s_vec,
sp[2]->s_vec, sp[3]->s_vec, n2);
dsp_add(sigsqrt_perform, 3, sp[3]->s_vec, sp[3]->s_vec, n2);
}
static void sigframp_setup(void)
{
sigframp_class = class_new(gensym("framp~"), sigframp_new, 0,
sizeof(t_sigframp), 0, 0);
CLASS_MAINSIGNALIN(sigframp_class, t_sigframp, x_f);
class_addmethod(sigframp_class, (t_method)sigframp_dsp, gensym("dsp"),
A_CANT, 0);