aboutsummaryrefslogtreecommitdiff
path: root/pd/extra/pique
diff options
context:
space:
mode:
authorGuenter Geiger <ggeiger@users.sourceforge.net>2002-07-29 17:06:19 +0000
committerGuenter Geiger <ggeiger@users.sourceforge.net>2002-07-29 17:06:19 +0000
commit57045df5fe3ec557e57dc7434ac1a07b5521bffc (patch)
tree7174058b41b73c808107c7090d9a4e93ee202341 /pd/extra/pique
parentda38b3424229e59f956252c3d89895e43e84e278 (diff)
This commit was generated by cvs2svn to compensate for changes in r58,
which included commits to RCS files with non-trunk default branches. svn path=/trunk/; revision=59
Diffstat (limited to 'pd/extra/pique')
-rw-r--r--pd/extra/pique/makefile94
-rw-r--r--pd/extra/pique/pique.c238
2 files changed, 332 insertions, 0 deletions
diff --git a/pd/extra/pique/makefile b/pd/extra/pique/makefile
new file mode 100644
index 00000000..2a565566
--- /dev/null
+++ b/pd/extra/pique/makefile
@@ -0,0 +1,94 @@
+NAME=pique
+CSYM=pique
+
+current: pd_linux
+
+# ----------------------- NT -----------------------
+
+pd_nt: $(NAME).dll
+
+.SUFFIXES: .dll
+
+PDNTCFLAGS = /W3 /WX /DNT /DPD /nologo
+VC="C:\Program Files\Microsoft Visual Studio\Vc98"
+
+PDNTINCLUDE = /I. /I\tcl\include /I\ftp\pd\src /I$(VC)\include
+
+PDNTLDIR = $(VC)\lib
+PDNTLIB = $(PDNTLDIR)\libc.lib \
+ $(PDNTLDIR)\oldnames.lib \
+ $(PDNTLDIR)\kernel32.lib \
+ \ftp\pd\bin\pd.lib
+
+.c.dll:
+ cl $(PDNTCFLAGS) $(PDNTINCLUDE) /c $*.c
+ link /dll /export:$(CSYM)_setup $*.obj $(PDNTLIB)
+
+# ----------------------- IRIX 5.x -----------------------
+
+pd_irix5: $(NAME).pd_irix5
+
+.SUFFIXES: .pd_irix5
+
+SGICFLAGS5 = -o32 -DPD -DUNIX -DIRIX -O2
+
+SGIINCLUDE = -I../../src
+
+.c.pd_irix5:
+ cc $(SGICFLAGS5) $(SGIINCLUDE) -o $*.o -c $*.c
+ ld -elf -shared -rdata_shared -o $*.pd_irix5 $*.o
+ rm $*.o
+
+# ----------------------- IRIX 6.x -----------------------
+
+pd_irix6: $(NAME).pd_irix6
+
+.SUFFIXES: .pd_irix6
+
+SGICFLAGS6 = -n32 -DPD -DUNIX -DIRIX -DN32 -woff 1080,1064,1185 \
+ -OPT:roundoff=3 -OPT:IEEE_arithmetic=3 -OPT:cray_ivdep=true \
+ -Ofast=ip32
+
+.c.pd_irix6:
+ cc $(SGICFLAGS6) $(SGIINCLUDE) -o $*.o -c $*.c
+ ld -n32 -IPA -shared -rdata_shared -o $*.pd_irix6 $*.o
+ rm $*.o
+
+# ----------------------- LINUX i386 -----------------------
+
+pd_linux: $(NAME).pd_linux
+
+.SUFFIXES: .pd_linux
+
+LINUXCFLAGS = -DPD -O2 -funroll-loops -fomit-frame-pointer \
+ -Wall -W -Wshadow -Wstrict-prototypes -Werror \
+ -Wno-unused -Wno-parentheses -Wno-switch
+
+LINUXINCLUDE = -I../../src
+
+.c.pd_linux:
+ cc $(LINUXCFLAGS) $(LINUXINCLUDE) -o $*.o -c $*.c
+ ld -export_dynamic -shared -o $*.pd_linux $*.o -lc -lm
+ strip --strip-unneeded $*.pd_linux
+ rm -f $*.o ../$*.pd_linux
+ ln -s $*/$*.pd_linux ..
+
+# ----------------------- Mac OSX -----------------------
+
+pd_darwin: $(NAME).pd_darwin
+
+.SUFFIXES: .pd_darwin
+
+DARWINCFLAGS = -DPD -O2 -Wall -W -Wshadow -Wstrict-prototypes \
+ -Wno-unused -Wno-parentheses -Wno-switch
+
+.c.pd_darwin:
+ cc $(DARWINCFLAGS) $(LINUXINCLUDE) -o $*.o -c $*.c
+ cc -bundle -undefined suppress -flat_namespace -o $*.pd_darwin $*.o
+ rm -f $*.o ../$*.pd_darwin
+ ln -s $*/$*.pd_darwin ..
+
+# ----------------------------------------------------------
+
+clean:
+ rm -f *.o *.pd_* so_locations
diff --git a/pd/extra/pique/pique.c b/pd/extra/pique/pique.c
new file mode 100644
index 00000000..aaf80350
--- /dev/null
+++ b/pd/extra/pique/pique.c
@@ -0,0 +1,238 @@
+/* Copyright (c) 1999 Miller Puckette. The
+contents of this file are free for any use, but BOTH THE AUTHOR AND UCSD
+DISCLAIM ALL WARRANTIES related to it. Although not written in Java, this
+still should not be used to control any machinery containing a sharp blade or
+combustible materiel, or as part of any life support system or weapon. */
+
+#include "m_pd.h"
+#include <math.h>
+#include <stdio.h>
+#ifdef NT
+#pragma warning( disable : 4244 )
+#pragma warning( disable : 4305 )
+#endif
+
+static t_class *pique_class;
+
+typedef struct _pique
+{
+ t_object x_obj;
+ int x_n;
+ float x_errthresh;
+ float *x_freq;
+ float *x_amp;
+ float *x_ampre;
+ float *x_ampim;
+} t_pique;
+
+static void *pique_new(t_floatarg f)
+{
+ int n = f;
+ t_pique *x = (t_pique *)pd_new(pique_class);
+ if (n < 1) n = 100;
+ x->x_n = n;
+ x->x_errthresh = 0;
+ x->x_freq = t_getbytes(n * sizeof(*x->x_freq));
+ x->x_amp = t_getbytes(n * sizeof(*x->x_amp));
+ x->x_ampre = t_getbytes(n * sizeof(*x->x_ampre));
+ x->x_ampim = t_getbytes(n * sizeof(*x->x_ampim));
+ outlet_new(&x->x_obj, &s_list);
+ return (x);
+}
+
+static float hanning(float pidetune, float sinpidetune)
+{
+ float pi = 3.14159;
+ if (pidetune < 0.01 && pidetune > -0.01) return (1);
+ else if (pidetune > 3.14 && pidetune < 3.143) return (0.5);
+ else if (pidetune < -3.14 && pidetune > -3.143) return (0.5);
+ else return (sinpidetune/pidetune - 0.5 *
+ (sinpidetune/(pidetune+pi) + sinpidetune/(pidetune-pi)));
+}
+
+static float peakerror(float *fpreal, float *fpimag, float pidetune,
+ float norm, float peakreal, float peakimag)
+{
+ float sinpidetune = sin(pidetune);
+ float cospidetune = cos(pidetune);
+ float windowshould = hanning(pidetune, sinpidetune);
+ float realshould = windowshould * (
+ peakreal * cospidetune + peakimag * sinpidetune);
+ float imagshould = windowshould * (
+ peakimag * cospidetune - peakreal * sinpidetune);
+ float realgot = norm * (fpreal[0] - 0.5 * (fpreal[1] + fpreal[-1]));
+ float imaggot = norm * (fpimag[0] - 0.5 * (fpimag[1] + fpimag[-1]));
+ float realdev = realshould - realgot, imagdev = imagshould - imaggot;
+
+ /* post("real %f->%f; imag %f->%f", realshould, realgot,
+ imagshould, imaggot); */
+ return (realdev * realdev + imagdev * imagdev);
+}
+
+static void pique_doit(int npts, t_float *fpreal, t_float *fpimag,
+ int npeak, int *nfound, t_float *fpfreq, t_float *fpamp,
+ t_float *fpampre, t_float *fpampim, float errthresh)
+{
+ float srate = sys_getsr(); /* not sure how to get this correctly */
+ float oneovern = 1.0/ (float)npts;
+ float fperbin = srate * oneovern;
+ float pow1, pow2 = 0, pow3 = 0, pow4 = 0, pow5 = 0;
+ float re1, re2 = 0, re3 = *fpreal;
+ float im1, im2 = 0, im3 = 0, powthresh, relativeerror;
+ int count, peakcount = 0, n2 = (npts >> 1);
+ float *fp1, *fp2;
+ for (count = n2, fp1 = fpreal, fp2 = fpimag, powthresh = 0;
+ count--; fp1++, fp2++)
+ powthresh += (*fp1) * (*fp1) + (*fp2) * (*fp2) ;
+ powthresh *= 0.00001;
+ for (count = 1; count < n2; count++)
+ {
+ float windreal, windimag, pi = 3.14159;
+ float detune, pidetune, sinpidetune, cospidetune,
+ ampcorrect, freqout, ampout, ampoutreal, ampoutimag;
+ float rpeak, rpeaknext, rpeakprev;
+ float ipeak, ipeaknext, ipeakprev;
+ float errleft, errright;
+ fpreal++;
+ fpimag++;
+ re1 = re2;
+ re2 = re3;
+ re3 = *fpreal;
+ im1 = im2;
+ im2 = im3;
+ im3 = *fpimag;
+ if (count < 2) continue;
+ pow1 = pow2;
+ pow2 = pow3;
+ pow3 = pow4;
+ pow4 = pow5;
+ /* get Hanning-windowed spectrum by convolution */
+ windreal = re2 - 0.5 * (re1 + re3);
+ windimag = im2 - 0.5 * (im1 + im3);
+ pow5 = windreal * windreal + windimag * windimag;
+ /* if (count < 30) post("power %f", pow5); */
+ if (count < 5) continue;
+ /* check for a peak. The actual bin is count-3. */
+ if (pow3 <= pow2 || pow3 <= pow4 || pow3 <= pow1 || pow3 <= pow5
+ || pow3 < powthresh)
+ continue;
+ /* go back for the raw FFT values around the peak. */
+ rpeak = fpreal[-3];
+ rpeaknext = fpreal[-2];
+ rpeakprev = fpreal[-4];
+ ipeak = fpimag[-3];
+ ipeaknext = fpimag[-2];
+ ipeakprev = fpimag[-4];
+ /* recalculate Hanning-windowed spectrum by convolution */
+ windreal = rpeak - 0.5 * (rpeaknext + rpeakprev);
+ windimag = ipeak - 0.5 * (ipeaknext + ipeakprev);
+
+ detune = ((rpeakprev - rpeaknext) *
+ (2.0 * rpeak - rpeakprev - rpeaknext) +
+ (ipeakprev - ipeaknext) *
+ (2.0 * ipeak - ipeakprev - ipeaknext)) /
+ (4.0 * pow3);
+ /* if (count < 30) post("detune %f", detune); */
+ if (detune > 0.7 || detune < -0.7) continue;
+ /* the frequency is the sum of the bin frequency and detuning */
+ freqout = fperbin * ((float)(count-3) + detune);
+ pidetune = pi * detune;
+ sinpidetune = sin(pidetune);
+ cospidetune = cos(pidetune);
+ ampcorrect = 1.0 / hanning(pidetune, sinpidetune);
+ /* Multiply by 2 to get real-sinusoid peak amplitude
+ and divide by N to normalize FFT */
+ ampcorrect *= 2. * oneovern;
+ /* amplitude is peak height, corrected for Hanning window shape */
+
+ ampout = ampcorrect * sqrt(pow3);
+ ampoutreal = ampcorrect *
+ (windreal * cospidetune - windimag * sinpidetune);
+ ampoutimag = ampcorrect *
+ (windreal * sinpidetune + windimag * cospidetune);
+ if (errthresh > 0)
+ {
+ /* post("peak %f %f", freqout, ampout); */
+ errleft = peakerror(fpreal-4, fpimag-4, pidetune+pi,
+ 2. * oneovern, ampoutreal, ampoutimag);
+ errright = peakerror(fpreal-2, fpimag-2, pidetune-pi,
+ 2. * oneovern, ampoutreal, ampoutimag);
+ relativeerror = (errleft + errright)/(ampout * ampout);
+ if (relativeerror > errthresh) continue;
+ }
+ /* post("power %f, error %f, relative %f",
+ pow3, errleft + errright, relativeerror); */
+ *fpfreq++ = freqout;
+ *fpamp++ = ampout;
+ *fpampre++ = ampoutreal;
+ *fpampim++ = ampoutimag;
+ if (++peakcount == npeak) break;
+ }
+ *nfound = peakcount;
+}
+
+static void pique_list(t_pique *x, t_symbol *s, int argc, t_atom *argv)
+{
+ int npts = atom_getintarg(0, argc, argv);
+ t_symbol *symreal = atom_getsymbolarg(1, argc, argv);
+ t_symbol *symimag = atom_getsymbolarg(2, argc, argv);
+ int npeak = atom_getintarg(3, argc, argv);
+ int n;
+ t_garray *a;
+ t_float *fpreal, *fpimag;
+ if (npts < 8 || npeak < 1) error("pique: bad npoints or npeak");
+ if (npeak > x->x_n) npeak = x->x_n;
+ if (!(a = (t_garray *)pd_findbyclass(symreal, garray_class)) ||
+ !garray_getfloatarray(a, &n, &fpreal) ||
+ n < npts)
+ error("%s: missing or bad array", symreal->s_name);
+ else if (!(a = (t_garray *)pd_findbyclass(symimag, garray_class)) ||
+ !garray_getfloatarray(a, &n, &fpimag) ||
+ n < npts)
+ error("%s: missing or bad array", symimag->s_name);
+ else
+ {
+ int nfound, i;
+ float *fpfreq = x->x_freq;
+ float *fpamp = x->x_amp;
+ float *fpampre = x->x_ampre;
+ float *fpampim = x->x_ampim;
+ pique_doit(npts, fpreal, fpimag, npeak,
+ &nfound, fpfreq, fpamp, fpampre, fpampim, x->x_errthresh);
+ for (i = 0; i < nfound; i++, fpamp++, fpfreq++, fpampre++, fpampim++)
+ {
+ t_atom at[5];
+ SETFLOAT(at, (float)i);
+ SETFLOAT(at+1, *fpfreq);
+ SETFLOAT(at+2, *fpamp);
+ SETFLOAT(at+3, *fpampre);
+ SETFLOAT(at+4, *fpampim);
+ outlet_list(x->x_obj.ob_outlet, &s_list, 5, at);
+ }
+ }
+}
+
+static void pique_errthresh(t_pique *x, t_floatarg f)
+{
+ x->x_errthresh = f;
+}
+
+static void pique_free(t_pique *x)
+{
+ int n = x->x_n;
+ t_freebytes(x->x_freq, n * sizeof(*x->x_freq));
+ t_freebytes(x->x_amp, n * sizeof(*x->x_amp));
+ t_freebytes(x->x_ampre, n * sizeof(*x->x_ampre));
+ t_freebytes(x->x_ampim, n * sizeof(*x->x_ampim));
+}
+
+void pique_setup(void)
+{
+ pique_class = class_new(gensym("pique"), (t_newmethod)pique_new,
+ (t_method)pique_free, sizeof(t_pique),0, A_DEFFLOAT, 0);
+ class_addlist(pique_class, pique_list);
+ class_addmethod(pique_class, (t_method)pique_errthresh,
+ gensym("errthresh"), A_FLOAT, 0);
+ post("pique 0.1 for PD version 23");
+}
+