From faada59567f8cb252f4a909116595ce309ff5828 Mon Sep 17 00:00:00 2001 From: "N.N." Date: Fri, 23 May 2003 12:29:55 +0000 Subject: This commit was generated by cvs2svn to compensate for changes in r647, which included commits to RCS files with non-trunk default branches. svn path=/trunk/externals/miXed/; revision=648 --- cyclone/sickle/Scope.c | 1043 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1043 insertions(+) create mode 100644 cyclone/sickle/Scope.c (limited to 'cyclone/sickle/Scope.c') diff --git a/cyclone/sickle/Scope.c b/cyclone/sickle/Scope.c new file mode 100644 index 0000000..75e825d --- /dev/null +++ b/cyclone/sickle/Scope.c @@ -0,0 +1,1043 @@ +/* Copyright (c) 2002-2003 krzYszcz and others. + * For information on usage and redistribution, and for a DISCLAIMER OF ALL + * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ + +/* LATER cache gui commands */ +/* LATER think about resizing scheme. Currently mouse events are not bound + to any part of Scope~'s 'widget' as such, but to a special item, which is + created only for a selected Scope~. For the other scheme see the 'comment' + class (no indicator there, though -- neither a handle, nor a pointer change). + One way or the other, the traffic from the gui layer should be kept possibly + low, at least in run-mode. */ + +#include +#include +#include "m_pd.h" +#include "g_canvas.h" +#include "common/loud.h" +#include "common/grow.h" +#include "unstable/forky.h" +#include "sickle/sic.h" + +//#define SCOPE_DEBUG + +/* these are powers of 2 + margins */ +#define SCOPE_DEFWIDTH 130 /* CHECKED */ +#define SCOPE_MINWIDTH 66 +#define SCOPE_DEFHEIGHT 130 /* CHECKED */ +#define SCOPE_MINHEIGHT 34 +#define SCOPE_DEFPERIOD 256 +#define SCOPE_MINPERIOD 2 +#define SCOPE_MAXPERIOD 8092 +#define SCOPE_DEFBUFSIZE 128 +#define SCOPE_MINBUFSIZE 8 +#define SCOPE_MAXBUFSIZE 800 /* LATER rethink */ +#define SCOPE_WARNBUFSIZE 256 +#define SCOPE_DEFMINVAL -1. +#define SCOPE_DEFMAXVAL 1. +#define SCOPE_DEFDELAY 0 +#define SCOPE_MINDELAY 0 +#define SCOPE_TRIGLINEMODE 0 +#define SCOPE_TRIGUPMODE 1 +#define SCOPE_TRIGDOWNMODE 2 +#define SCOPE_DEFTRIGMODE SCOPE_TRIGLINEMODE +#define SCOPE_MINTRIGMODE SCOPE_TRIGLINEMODE +#define SCOPE_MAXTRIGMODE SCOPE_TRIGDOWNMODE +#define SCOPE_DEFTRIGLEVEL 0. +#define SCOPE_MINCOLOR 0 +#define SCOPE_MAXCOLOR 255 +#define SCOPE_DEFFGRED 102 +#define SCOPE_DEFFGGREEN 255 +#define SCOPE_DEFFGBLUE 51 +#define SCOPE_DEFBGRED 135 +#define SCOPE_DEFBGGREEN 135 +#define SCOPE_DEFBGBLUE 135 +#define SCOPE_SELCOLOR "#8080ff" /* a bit lighter shade of blue */ +#define SCOPE_FGWIDTH 0.7 /* line width is float */ +#define SCOPE_GRIDWIDTH 0.9 +#define SCOPE_SELBDWIDTH 3.0 +#define SCOPEHANDLE_WIDTH 10 /* item size is int */ +#define SCOPEHANDLE_HEIGHT 10 +/* these are performance-related hacks, LATER investigate */ +#define SCOPE_GUICHUNKMONO 16 +#define SCOPE_GUICHUNKXY 32 + +typedef struct _scope +{ + t_sic x_sic; + t_glist *x_glist; + t_canvas *x_canvas; /* also an 'isvised' flag */ + char x_tag[64]; + char x_fgtag[64]; + char x_bgtag[64]; + char x_gridtag[64]; + int x_width; + int x_height; + float x_minval; + float x_maxval; + int x_delay; + int x_trigmode; + float x_triglevel; + unsigned char x_fgred; + unsigned char x_fggreen; + unsigned char x_fgblue; + unsigned char x_bgred; + unsigned char x_bggreen; + unsigned char x_bgblue; + int x_xymode; + float *x_xbuffer; + float *x_ybuffer; + float x_xbufini[SCOPE_DEFBUFSIZE]; + float x_ybufini[SCOPE_DEFBUFSIZE]; + int x_allocsize; + int x_bufsize; + int x_bufphase; + int x_period; + int x_phase; + int x_precount; + int x_retrigger; + float x_ksr; + float x_currx; + float x_curry; + float x_trigx; + int x_frozen; + t_clock *x_clock; + t_pd *x_handle; +} t_scope; + +typedef struct _scopehandle +{ + t_pd h_pd; + t_scope *h_master; + t_symbol *h_bindsym; + char h_pathname[64]; + char h_outlinetag[64]; + int h_dragon; + int h_dragx; + int h_dragy; +} t_scopehandle; + +static t_class *scope_class; +static t_class *scopehandle_class; + +static void scope_clear(t_scope *x, int withdelay) +{ + x->x_bufphase = 0; + x->x_phase = 0; + x->x_precount = (withdelay ? (int)(x->x_delay * x->x_ksr) : 0); + /* CHECKED delay does not matter (refman is wrong) */ + x->x_retrigger = (x->x_trigmode != SCOPE_TRIGLINEMODE); + x->x_trigx = x->x_triglevel; +} + +static t_int *scope_monoperform(t_int *w) +{ + t_scope *x = (t_scope *)(w[1]); + int bufphase = x->x_bufphase; + int bufsize = x->x_bufsize; + if (bufphase < bufsize) + { + int nblock = (int)(w[2]); + if (x->x_precount >= nblock) + x->x_precount -= nblock; + else + { + t_float *in = (t_float *)(w[3]); + int phase = x->x_phase; + int period = x->x_period; + float *bp1 = x->x_xbuffer + bufphase; + float *bp2 = x->x_ybuffer + bufphase; + float currx = x->x_currx; + if (x->x_precount > 0) + { + nblock -= x->x_precount; + in += x->x_precount; + x->x_precount = 0; + } + while (x->x_retrigger) + { + float triglevel = x->x_triglevel; + if (x->x_trigmode == SCOPE_TRIGUPMODE) + { + if (x->x_trigx < triglevel) + { + while (nblock--) if (*in++ >= triglevel) + { + x->x_retrigger = 0; + break; + } + } + else while (nblock--) if (*in++ < triglevel) + { + x->x_trigx = triglevel - 1.; + break; + } + } + else + { + if (x->x_trigx > triglevel) + { + while (nblock--) if (*in++ <= triglevel) + { + x->x_retrigger = 0; + break; + } + } + else while (nblock--) if (*in++ > triglevel) + { + x->x_trigx = triglevel + 1.; + break; + } + } + if (nblock <= 0) + return (w + 4); + } + while (nblock--) + { + if (phase) + { + float f = *in++; + /* CHECKED */ + if ((currx < 0 && (f < currx || f > -currx)) || + (currx > 0 && (f > currx || f < -currx))) + currx = f; + } + else currx = *in++; + if (currx != currx) + currx = 0.; /* CHECKED NaNs bashed to zeros */ + if (++phase == period) + { + phase = 0; + if (++bufphase == bufsize) + { + *bp1 = *bp2 = currx; + clock_delay(x->x_clock, 0); + break; + } + else *bp1++ = *bp2++ = currx; + } + } + x->x_currx = currx; + x->x_bufphase = bufphase; + x->x_phase = phase; + } + } + return (w + 4); +} + +static t_int *scope_xyperform(t_int *w) +{ + t_scope *x = (t_scope *)(w[1]); + int bufphase = x->x_bufphase; + int bufsize = x->x_bufsize; + if (bufphase < bufsize) + { + int nblock = (int)(w[2]); + if (x->x_precount >= nblock) + x->x_precount -= nblock; + else + { + t_float *in1 = (t_float *)(w[3]); + t_float *in2 = (t_float *)(w[4]); + int phase = x->x_phase; + int period = x->x_period; + float freq = 1. / period; + float *bp1 = x->x_xbuffer + bufphase; + float *bp2 = x->x_ybuffer + bufphase; + float currx = x->x_currx; + float curry = x->x_curry; + if (x->x_precount > 0) + { + nblock -= x->x_precount; + in1 += x->x_precount; + in2 += x->x_precount; + x->x_precount = 0; + } + if (x->x_retrigger) + { + /* CHECKME and FIXME */ + x->x_retrigger = 0; + } + while (nblock--) + { + if (phase) + { + /* CHECKME */ + currx += *in1++; + curry += *in2++; + } + else + { + currx = *in1++; + curry = *in2++; + } + if (currx != currx) + currx = 0.; /* CHECKME NaNs bashed to zeros */ + if (curry != curry) + curry = 0.; /* CHECKME NaNs bashed to zeros */ + if (++phase == period) + { + phase = 0; + if (++bufphase == bufsize) + { + *bp1 = currx * freq; + *bp2 = curry * freq; + clock_delay(x->x_clock, 0); + break; + } + else + { + *bp1++ = currx * freq; + *bp2++ = curry * freq; + } + } + } + x->x_currx = currx; + x->x_curry = curry; + x->x_bufphase = bufphase; + x->x_phase = phase; + } + } + return (w + 5); +} + +static void scope_setxymode(t_scope *x, int xymode); + +static void scope_dsp(t_scope *x, t_signal **sp) +{ + x->x_ksr = sp[0]->s_sr * 0.001; + scope_setxymode(x, + forky_hasfeeders((t_object *)x, x->x_glist, 1, &s_signal)); + if (x->x_xymode) + dsp_add(scope_xyperform, 4, x, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec); + else + dsp_add(scope_monoperform, 3, x, sp[0]->s_n, sp[0]->s_vec); +} + +static t_canvas *scope_getcanvas(t_scope *x, t_glist *glist) +{ + if (glist != x->x_glist) + { + bug("scope_getcanvas"); + x->x_glist = glist; + } + return (x->x_canvas = glist_getcanvas(glist)); +} + +/* answers the question: ``can we draw and where to?'' */ +static t_canvas *scope_isvisible(t_scope *x) +{ + return (glist_isvisible(x->x_glist) ? x->x_canvas : 0); +} + +static void scope_period(t_scope *x, t_symbol *s, int ac, t_atom *av) +{ + t_float period = (s ? x->x_period : SCOPE_DEFPERIOD); + int result = loud_floatarg(*(t_pd *)x, (s ? 0 : 2), ac, av, &period, + SCOPE_MINPERIOD, SCOPE_MAXPERIOD, + /* LATER rethink warning rules */ + (s ? LOUD_CLIP : LOUD_CLIP | LOUD_WARN), + (s ? 0 : LOUD_WARN), "samples per element"); + if (!s || result == LOUD_ARGOK || result == LOUD_ARGOVER) + { + x->x_period = (int)period; + scope_clear(x, 0); + } +} + +static void scope_float(t_scope *x, t_float f) +{ + t_atom at; + SETFLOAT(&at, f); + scope_period(x, &s_float, 1, &at); +} + +static void scope_bufsize(t_scope *x, t_symbol *s, int ac, t_atom *av) +{ + t_float bufsize = (s ? x->x_bufsize : SCOPE_DEFBUFSIZE); + int result = loud_floatarg(*(t_pd *)x, (s ? 0 : 4), ac, av, &bufsize, + SCOPE_MINBUFSIZE, SCOPE_WARNBUFSIZE, + /* LATER rethink warning rules */ + (s ? LOUD_CLIP : LOUD_CLIP | LOUD_WARN), + (s ? 0 : LOUD_WARN), "display elements"); + if (result == LOUD_ARGOVER) + { + bufsize = (s ? x->x_bufsize : SCOPE_DEFBUFSIZE); + result = loud_floatarg(*(t_pd *)x, (s ? 0 : 4), ac, av, &bufsize, + 0, SCOPE_MAXBUFSIZE, 0, LOUD_CLIP | LOUD_WARN, + "display elements"); + } + if (!s) + { + x->x_allocsize = SCOPE_DEFBUFSIZE; + x->x_bufsize = 0; + x->x_xbuffer = x->x_xbufini; + x->x_ybuffer = x->x_ybufini; + } + if (!s || result == LOUD_ARGOK) + { + int newsize = (int)bufsize; + if (newsize > x->x_allocsize) + { + int nrequested = newsize; + int allocsize = x->x_allocsize; + int oldsize = x->x_bufsize; + x->x_xbuffer = grow_withdata(&nrequested, &oldsize, + &allocsize, x->x_xbuffer, + SCOPE_DEFBUFSIZE, x->x_xbufini, + sizeof(*x->x_xbuffer)); + if (nrequested == newsize) + { + allocsize = x->x_allocsize; + oldsize = x->x_bufsize; + x->x_ybuffer = grow_withdata(&nrequested, &oldsize, + &allocsize, x->x_ybuffer, + SCOPE_DEFBUFSIZE, x->x_ybufini, + sizeof(*x->x_ybuffer)); + } + if (nrequested == newsize) + { + x->x_allocsize = allocsize; + x->x_bufsize = newsize; + } + else + { + if (x->x_xbuffer != x->x_xbufini) + freebytes(x->x_xbuffer, + x->x_allocsize * sizeof(*x->x_xbuffer)); + if (x->x_ybuffer != x->x_ybufini) + freebytes(x->x_ybuffer, + x->x_allocsize * sizeof(*x->x_ybuffer)); + x->x_allocsize = SCOPE_DEFBUFSIZE; + x->x_bufsize = SCOPE_DEFBUFSIZE; + x->x_xbuffer = x->x_xbufini; + x->x_ybuffer = x->x_ybufini; + } + } + else x->x_bufsize = newsize; + scope_clear(x, 0); + } +} + +static void scope_range(t_scope *x, t_symbol *s, int ac, t_atom *av) +{ + t_float minval = (s ? x->x_minval : SCOPE_DEFMINVAL); + t_float maxval = (s ? x->x_maxval : SCOPE_DEFMAXVAL); + loud_floatarg(*(t_pd *)x, (s ? 0 : 5), ac, av, &minval, 0, 0, 0, 0, 0); + loud_floatarg(*(t_pd *)x, (s ? 1 : 6), ac, av, &maxval, 0, 0, 0, 0, 0); + /* CHECKME swapping, ignoring if equal */ + if (minval < maxval) + { + x->x_minval = minval; + x->x_maxval = maxval; + } + else if (minval > maxval) + { + x->x_minval = maxval; + x->x_maxval = minval; + } + else if (!s) + { + x->x_minval = SCOPE_DEFMINVAL; + x->x_maxval = SCOPE_DEFMAXVAL; + } +} + +static void scope_delay(t_scope *x, t_symbol *s, int ac, t_atom *av) +{ + t_float delay = (s ? x->x_delay : SCOPE_DEFDELAY); + int result = loud_floatarg(*(t_pd *)x, (s ? 0 : 7), ac, av, &delay, + SCOPE_MINDELAY, 0, + LOUD_CLIP | LOUD_WARN, 0, "delay"); + if (!s || result == LOUD_ARGOK) + x->x_delay = delay; +} + +static void scope_trigger(t_scope *x, t_symbol *s, int ac, t_atom *av) +{ + t_float trigmode = (s ? x->x_trigmode : SCOPE_DEFTRIGMODE); + loud_floatarg(*(t_pd *)x, (s ? 0 : 9), ac, av, &trigmode, + SCOPE_MINTRIGMODE, SCOPE_MAXTRIGMODE, + LOUD_CLIP | LOUD_WARN, LOUD_CLIP | LOUD_WARN, + "trigger mode"); + x->x_trigmode = (int)trigmode; + if (x->x_trigmode == SCOPE_TRIGLINEMODE) + x->x_retrigger = 0; +} + +static void scope_triglevel(t_scope *x, t_symbol *s, int ac, t_atom *av) +{ + t_float triglevel = (s ? x->x_triglevel : SCOPE_DEFTRIGLEVEL); + loud_floatarg(*(t_pd *)x, (s ? 0 : 10), ac, av, &triglevel, 0, 0, 0, 0, 0); + x->x_triglevel = triglevel; +} + +static void scope_frgb(t_scope *x, t_symbol *s, int ac, t_atom *av) +{ + t_float fgred = (s ? x->x_fgred : SCOPE_DEFFGRED); + t_float fggreen = (s ? x->x_fggreen : SCOPE_DEFFGGREEN); + t_float fgblue = (s ? x->x_fgblue : SCOPE_DEFFGBLUE); + t_canvas *cv; + loud_floatarg(*(t_pd *)x, (s ? 0 : 11), ac, av, &fgred, + SCOPE_MINCOLOR, SCOPE_MAXCOLOR, + LOUD_CLIP | LOUD_WARN, LOUD_CLIP | LOUD_WARN, "color"); + loud_floatarg(*(t_pd *)x, (s ? 1 : 12), ac, av, &fggreen, + SCOPE_MINCOLOR, SCOPE_MAXCOLOR, + LOUD_CLIP | LOUD_WARN, LOUD_CLIP | LOUD_WARN, "color"); + loud_floatarg(*(t_pd *)x, (s ? 2 : 13), ac, av, &fgblue, + SCOPE_MINCOLOR, SCOPE_MAXCOLOR, + LOUD_CLIP | LOUD_WARN, LOUD_CLIP | LOUD_WARN, "color"); + x->x_fgred = (int)fgred; + x->x_fggreen = (int)fggreen; + x->x_fgblue = (int)fgblue; + if (cv = scope_isvisible(x)) + sys_vgui(".x%x.c itemconfigure %s -fill #%2.2x%2.2x%2.2x\n", + cv, x->x_fgtag, x->x_fgred, x->x_fggreen, x->x_fgblue); +} + +static void scope_brgb(t_scope *x, t_symbol *s, int ac, t_atom *av) +{ + t_float bgred = (s ? x->x_bgred : SCOPE_DEFBGRED); + t_float bggreen = (s ? x->x_bggreen : SCOPE_DEFBGGREEN); + t_float bgblue = (s ? x->x_bgblue : SCOPE_DEFBGBLUE); + t_canvas *cv; + loud_floatarg(*(t_pd *)x, (s ? 0 : 14), ac, av, &bgred, + SCOPE_MINCOLOR, SCOPE_MAXCOLOR, + LOUD_CLIP | LOUD_WARN, LOUD_CLIP | LOUD_WARN, "color"); + loud_floatarg(*(t_pd *)x, (s ? 1 : 15), ac, av, &bggreen, + SCOPE_MINCOLOR, SCOPE_MAXCOLOR, + LOUD_CLIP | LOUD_WARN, LOUD_CLIP | LOUD_WARN, "color"); + loud_floatarg(*(t_pd *)x, (s ? 2 : 16), ac, av, &bgblue, + SCOPE_MINCOLOR, SCOPE_MAXCOLOR, + LOUD_CLIP | LOUD_WARN, LOUD_CLIP | LOUD_WARN, "color"); + x->x_bgred = (int)bgred; + x->x_bggreen = (int)bggreen; + x->x_bgblue = (int)bgblue; + if (cv = scope_isvisible(x)) + sys_vgui(".x%x.c itemconfigure %s -fill #%2.2x%2.2x%2.2x\n", + cv, x->x_bgtag, x->x_bgred, x->x_bggreen, x->x_bgblue); +} + +static void scope_getrect(t_gobj *z, t_glist *glist, + int *xp1, int *yp1, int *xp2, int *yp2) +{ + t_scope *x = (t_scope *)z; + float x1, y1, x2, y2; + x1 = text_xpix((t_text *)x, glist); + y1 = text_ypix((t_text *)x, glist); + x2 = x1 + x->x_width; + y2 = y1 + x->x_height; + *xp1 = x1; + *yp1 = y1; + *xp2 = x2; + *yp2 = y2; +} + +static void scope_displace(t_gobj *z, t_glist *glist, int dx, int dy) +{ + t_scope *x = (t_scope *)z; + t_text *t = (t_text *)z; + t->te_xpix += dx; + t->te_ypix += dy; + if (glist_isvisible(glist)) + { + t_canvas *cv = scope_getcanvas(x, glist); + sys_vgui(".x%x.c move %s %d %d\n", cv, x->x_tag, dx, dy); + canvas_fixlinesfor(cv, t); + } +} + +static void scope_select(t_gobj *z, t_glist *glist, int state) +{ + t_scope *x = (t_scope *)z; + t_canvas *cv = scope_getcanvas(x, glist); + t_scopehandle *sh = (t_scopehandle *)x->x_handle; + if (state) + { + int x1, y1, x2, y2; + scope_getrect(z, glist, &x1, &y1, &x2, &y2); + + sys_vgui(".x%x.c itemconfigure %s -outline blue -width %f -fill %s\n", + cv, x->x_bgtag, SCOPE_SELBDWIDTH, SCOPE_SELCOLOR); + + sys_vgui("canvas %s -width %d -height %d -bg #fedc00 -bd 0\n", + sh->h_pathname, SCOPEHANDLE_WIDTH, SCOPEHANDLE_HEIGHT); + sys_vgui(".x%x.c create window %f %f -anchor nw\ + -width %d -height %d -window %s -tags %s\n", + cv, x2 - (SCOPEHANDLE_WIDTH - SCOPE_SELBDWIDTH), + y2 - (SCOPEHANDLE_HEIGHT - SCOPE_SELBDWIDTH), + SCOPEHANDLE_WIDTH, SCOPEHANDLE_HEIGHT, + sh->h_pathname, x->x_tag); + sys_vgui("bind %s