/* Copyright (c) 2007 Mathieu Bouchard Copyright (c) 1997-1999 Miller Puckette. For information on usage and redistribution, and for a DISCLAIMER OF ALL WARRANTIES, see the file "LICENSE.txt" in this distribution. */ #define PD_PLUSPLUS_FACE #include "desire.h" #include "s_stuff.h" #include #include #include #include #include #include #ifdef UNISTD #include #include #include #include #include #endif #ifdef MSW #include #include #endif #ifdef MSW #include #else #include #include #include #include #include #define SOCKET_ERROR -1 #endif #ifdef MSW #include #endif #if defined (__APPLE__) || defined (__FreeBSD__) #define HZ CLK_TCK #endif #ifndef HAVE_ALLOCA #ifdef _WIN32 #define HAVE_ALLOCA 0 /* LATER this should be set by configure script! */ #else #define HAVE_ALLOCA 1 /* LATER this should be set by configure script! */ #endif #endif #define a_float a_w.w_float #define a_symbol a_w.w_symbol #define a_pointer a_w.w_gpointer #define LIST_NGETBYTE 100 /* bigger that this we use alloc, not alloca */ /* #include */ #ifdef MSW #include #else #include #endif #define LOGTEN 2.302585092994 #undef min #undef max //conflict with min,max //using namespace std; float mtof(float f) {return f>-1500 ? 8.17579891564 * exp(.0577622650 * min(f,1499.f)) : 0;} float ftom(float f) {return f>0 ? 17.3123405046 * log(.12231220585 * f) : -1500;} float powtodb(float f) {return f>0 ? max(100 + 10./LOGTEN * log(f),0.) : 0;} float rmstodb(float f) {return f>0 ? max(100 + 20./LOGTEN * log(f),0.) : 0;} float dbtopow(float f) {return f>0 ? exp((LOGTEN * 0.1 ) * (min(f,870.f)-100.)) : 0;} float dbtorms(float f) {return f>0 ? exp((LOGTEN * 0.05) * (min(f,485.f)-100.)) : 0;} /* ------------- corresponding objects ----------------------- */ #define FUNC1(C,EXPR) \ static t_class *C##_class; \ static void *C##_new() { \ t_object *x = (t_object *)pd_new(C##_class); \ outlet_new(x, &s_float); return x;} \ static void C##_float(t_object *x, t_float a) {outlet_float(x->outlet, EXPR);} #define FUNC1DECL(C,SYM) \ C##_class = class_new2(SYM,C##_new,0,sizeof(t_object),0,""); \ class_addfloat(C##_class, (t_method)C##_float); \ class_sethelpsymbol(C##_class,s); FUNC1(mtof, mtof(a)) FUNC1(ftom, ftom(a)) FUNC1(powtodb,powtodb(a)) FUNC1(rmstodb,rmstodb(a)) FUNC1(dbtorms,dbtorms(a)) FUNC1(dbtopow,dbtopow(a)) /* -------------------------- openpanel ------------------------------ */ static t_class *openpanel_class; struct t_openpanel : t_object { t_symbol *s; t_symbol *path; }; static void *openpanel_new(t_symbol *s) { t_openpanel *x = (t_openpanel *)pd_new(openpanel_class); x->s = symprintf("d%lx",(t_int)x); x->path = s; pd_bind(x,x->s); outlet_new(x,&s_symbol); return x; } static void openpanel_bang(t_openpanel *x) { sys_vgui("pdtk_openpanel {%s} {%s}\n", x->s->name, (x->path&&x->path->name)?x->path->name:"\"\""); } static void openpanel_symbol(t_openpanel *x, t_symbol *s) { sys_vgui("pdtk_openpanel {%s} {%s}\n", x->s->name, (s && s->name) ? s->name : "\"\""); } static void openpanel_callback(t_openpanel *x, t_symbol *s) {outlet_symbol(x->outlet, s);} static void openpanel_path(t_openpanel *x, t_symbol *s) {x->path=s;} static void openpanel_free(t_openpanel *x) {pd_unbind(x, x->s);} static void openpanel_setup() { t_class *c = openpanel_class = class_new2("openpanel",openpanel_new,openpanel_free,sizeof(t_openpanel),0,"S"); class_addbang(c, openpanel_bang); class_addmethod2(c, openpanel_path, "path","s"); class_addmethod2(c, openpanel_callback,"callback","s"); class_addsymbol(c, openpanel_symbol); } /* -------------------------- savepanel ------------------------------ */ static t_class *savepanel_class; struct t_savepanel : t_object { t_symbol *s; t_symbol *path; }; static void *savepanel_new(t_symbol*s) { t_savepanel *x = (t_savepanel *)pd_new(savepanel_class); x->s = symprintf("d%lx",(t_int)x); x->path=s; pd_bind(x, x->s); outlet_new(x, &s_symbol); return x; } static void savepanel_bang(t_savepanel *x) { sys_vgui("pdtk_savepanel {%s} {%s}\n", x->s->name, (x->path&&x->path->name)?x->path->name:"\"\""); } static void savepanel_symbol(t_savepanel *x, t_symbol *s) { sys_vgui("pdtk_savepanel {%s} {%s}\n", x->s->name, (s && s->name) ? s->name : "\"\""); } static void savepanel_callback(t_savepanel *x, t_symbol *s) {outlet_symbol(x->outlet, s);} static void savepanel_free(t_savepanel *x) {pd_unbind(x, x->s);} static void savepanel_setup() { t_class *c = savepanel_class = class_new2("savepanel",savepanel_new,savepanel_free,sizeof(t_savepanel),0,"S"); class_addbang(c, savepanel_bang); class_addmethod2(c, openpanel_path, "path","s"); class_addmethod2(c, savepanel_callback, "callback","s"); class_addsymbol(c, savepanel_symbol); } /* ---------------------- key and its relatives ------------------ */ static t_symbol *key_sym, *keyup_sym, *keyname_sym; static t_class *key_class, *keyup_class, *keyname_class; struct t_key : t_object {}; static void *key_new() { t_key *x = (t_key *)pd_new(key_class); outlet_new(x, &s_float); pd_bind(x, key_sym); return x; } static void key_float(t_key *x, t_floatarg f) {outlet_float(x->outlet, f);} struct t_keyup : t_object {}; static void *keyup_new() { t_keyup *x = (t_keyup *)pd_new(keyup_class); outlet_new(x, &s_float); pd_bind(x, keyup_sym); return x; } static void keyup_float(t_keyup *x, t_floatarg f) {outlet_float(x->outlet, f);} struct t_keyname : t_object {}; static void *keyname_new() { t_keyname *x = (t_keyname *)pd_new(keyname_class); outlet_new(x, &s_float); outlet_new(x, &s_symbol); pd_bind(x, keyname_sym); return x; } static void keyname_list(t_keyname *x, t_symbol *s, int ac, t_atom *av) { outlet_symbol(x->out(1), atom_getsymbolarg(1, ac, av)); outlet_float( x->out(0), atom_getfloatarg( 0, ac, av)); } static void key_free( t_key *x) {pd_unbind(x, key_sym);} static void keyup_free( t_keyup *x) {pd_unbind(x, keyup_sym);} static void keyname_free(t_keyname *x) {pd_unbind(x, keyname_sym);} static void key_setup() { key_class = class_new2("key", key_new, key_free, sizeof(t_key), CLASS_NOINLET,""); keyup_class = class_new2("keyup", keyup_new, keyup_free, sizeof(t_keyup), CLASS_NOINLET,""); keyname_class = class_new2("keyname",keyname_new,keyname_free,sizeof(t_keyname),CLASS_NOINLET,""); class_addfloat(key_class, key_float); class_addfloat(keyup_class, keyup_float); class_addlist( keyname_class, keyname_list); class_sethelpsymbol(keyup_class, gensym("key")); class_sethelpsymbol(keyname_class, gensym("key")); key_sym = gensym("#key"); keyup_sym = gensym("#keyup"); keyname_sym = gensym("#keyname"); } static t_class *netsend_class; struct t_netsend : t_object { int fd; int protocol; }; static void *netsend_new(t_floatarg udpflag) { t_netsend *x = (t_netsend *)pd_new(netsend_class); outlet_new(x, &s_float); x->fd = -1; x->protocol = (udpflag != 0 ? SOCK_DGRAM : SOCK_STREAM); return x; } static void netsend_connect(t_netsend *x, t_symbol *hostname, t_floatarg fportno) { struct sockaddr_in server; int portno = (int)fportno; if (x->fd >= 0) {error("netsend_connect: already connected"); return;} /* create a socket */ int sockfd = socket(AF_INET, x->protocol, 0); if (sockfd < 0) {sys_sockerror("socket"); return;} /* connect socket using hostname provided in command line */ server.sin_family = AF_INET; struct hostent *hp = gethostbyname(hostname->name); if (!hp) {error("bad host?"); return;} #if 0 int intarg = 0; if (setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &intarg, sizeof(intarg)) < 0) error("setsockopt (SO_RCVBUF) failed"); #endif /* for stream (TCP) sockets, specify "nodelay" */ if (x->protocol == SOCK_STREAM) { int intarg = 1; if (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &intarg, sizeof(intarg)) < 0) error("setsockopt (TCP_NODELAY) failed"); } memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length); /* assign client port number */ server.sin_port = htons((u_short)portno); post("connecting to port %d", portno); /* try to connect. LATER make a separate thread to do this because it might block */ if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0) { sys_sockerror("connecting stream socket"); sys_closesocket(sockfd); return; } x->fd = sockfd; outlet_float(x->outlet, 1); } static void netsend_disconnect(t_netsend *x) { if (x->fd < 0) return; sys_closesocket(x->fd); x->fd = -1; outlet_float(x->outlet, 0); } static void netsend_send(t_netsend *x, t_symbol *s, int argc, t_atom *argv) { if (x->fd < 0) {error("netsend: not connected"); return;} t_binbuf *b = binbuf_new(); t_atom at; binbuf_add(b, argc, argv); SETSEMI(&at); binbuf_add(b, 1, &at); char *buf; int length, sent=0; binbuf_gettext(b, &buf, &length); char *bp = buf; while (sent < length) { static double lastwarntime; static double pleasewarn; double timebefore = sys_getrealtime(); int res = send(x->fd, buf, length-sent, 0); double timeafter = sys_getrealtime(); int late = (timeafter - timebefore > 0.005); if (late || pleasewarn) { if (timeafter > lastwarntime + 2) { post("netsend blocked %d msec", (int)(1000 * ((timeafter - timebefore) + pleasewarn))); pleasewarn = 0; lastwarntime = timeafter; } else if (late) pleasewarn += timeafter - timebefore; } if (res <= 0) { sys_sockerror("netsend"); netsend_disconnect(x); break; } else { sent += res; bp += res; } } free(buf); binbuf_free(b); } static void netsend_free(t_netsend *x) {netsend_disconnect(x);} static void netsend_setup() { netsend_class = class_new2("netsend",netsend_new,netsend_free,sizeof(t_netsend),0,"F"); class_addmethod2(netsend_class, netsend_connect, "connect","sf"); class_addmethod2(netsend_class, netsend_disconnect, "disconnect",""); class_addmethod2(netsend_class, netsend_send, "send","*"); } static t_class *netreceive_class; struct t_netreceive : t_object { t_outlet *msgout; t_outlet *connectout; int connectsocket; int nconnections; int udp; /* only used for sending (bidirectional socket to desire.tk) */ t_socketreceiver *sr; }; static void netreceive_notify(t_netreceive *x) { outlet_float(x->connectout, --x->nconnections); } static void netreceive_doit(t_netreceive *x, t_binbuf *b) { int natom = binbuf_getnatom(b); t_atom *at = binbuf_getvec(b); for (int msg = 0; msg < natom;) { int emsg; for (emsg = msg; emsg < natom && at[emsg].a_type != A_COMMA && at[emsg].a_type != A_SEMI; emsg++) {} if (emsg > msg) { for (int i = msg; i < emsg; i++) if (at[i].a_type == A_DOLLAR || at[i].a_type == A_DOLLSYM) { error("netreceive: got dollar sign in message"); goto nodice; } if (at[msg].a_type == A_FLOAT) { if (emsg > msg + 1) outlet_list(x->msgout, 0, emsg-msg, at + msg); else outlet_float(x->msgout, at[msg].a_float); } else if (at[msg].a_type == A_SYMBOL) outlet_anything(x->msgout, at[msg].a_symbol, emsg-msg-1, at + msg + 1); } nodice: msg = emsg + 1; } } static void netreceive_connectpoll(t_netreceive *x) { int fd = accept(x->connectsocket, 0, 0); if (fd < 0) post("netreceive: accept failed"); else { t_socketreceiver *y = socketreceiver_new((t_pd *)x, fd, (t_socketnotifier)netreceive_notify, x->msgout?(t_socketreceivefn)netreceive_doit:0, 0); sys_addpollfn(fd, (t_fdpollfn)socketreceiver_read, y); outlet_float(x->connectout, ++x->nconnections); y->next = x->sr; x->sr = y; } } extern "C" t_text *netreceive_new(t_symbol *compatflag, t_floatarg fportno, t_floatarg udpflag) { struct sockaddr_in server; int udp = !!udpflag; int old = !strcmp(compatflag->name , "old"); int intarg; /* create a socket */ int sockfd = socket(AF_INET, (udp ? SOCK_DGRAM : SOCK_STREAM), 0); if (sockfd < 0) {sys_sockerror("socket"); return 0;} server.sin_family = AF_INET; server.sin_addr.s_addr = INADDR_ANY; #if 1 /* ask OS to allow another Pd to reopen this port after we close it. */ intarg = 1; if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &intarg, sizeof(intarg)) < 0) post("setsockopt (SO_REUSEADDR) failed"); #endif #if 0 intarg = 0; if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &intarg, sizeof(intarg)) < 0) post("setsockopt (SO_RCVBUF) failed"); #endif /* Stream (TCP) sockets are set NODELAY */ if (!udp) { intarg = 1; if (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &intarg, sizeof(intarg)) < 0) post("setsockopt (TCP_NODELAY) failed"); } /* assign server port number */ server.sin_port = htons((u_short)fportno); /* name the socket */ if (bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0) { sys_sockerror("bind"); sys_closesocket(sockfd); return 0; } t_netreceive *x = (t_netreceive *)pd_new(netreceive_class); if (old) { /* old style, nonsecure version */ x->msgout = 0; } else x->msgout = outlet_new(x, &s_anything); if (udp) { /* datagram protocol */ t_socketreceiver *y = socketreceiver_new((t_pd *)x, sockfd, (t_socketnotifier)netreceive_notify, x->msgout ? (t_socketreceivefn)netreceive_doit : 0, 1); sys_addpollfn(sockfd, (t_fdpollfn)socketreceiver_read, y); x->connectout = 0; } else { /* streaming protocol */ if (listen(sockfd, 5) < 0) { sys_sockerror("listen"); sys_closesocket(sockfd); sockfd = -1; } else { sys_addpollfn(sockfd, (t_fdpollfn)netreceive_connectpoll, x); x->connectout = outlet_new(x, &s_float); } } x->connectsocket = sockfd; x->nconnections = 0; x->udp = udp; x->sr = 0; return x; } static void netreceive_free(t_netreceive *x) { /* LATER make me clean up open connections */ if (x->connectsocket >= 0) { sys_rmpollfn(x->connectsocket); sys_closesocket(x->connectsocket); } } static void netreceive_setup() { netreceive_class = class_new2("netreceive",netreceive_new,netreceive_free,sizeof(t_netreceive),CLASS_NOINLET,"FFS"); } extern "C" t_socketreceiver *netreceive_newest_receiver(t_netreceive *x) {return x->sr;} struct t_qlist : t_object { t_binbuf *binbuf; int onset; /* playback position */ t_clock *clock; float tempo; double whenclockset; float clockdelay; t_symbol *dir; t_canvas *canvas; int reentered; }; static void qlist_tick(t_qlist *x); static t_class *qlist_class; static void *qlist_new() { t_qlist *x = (t_qlist *)pd_new(qlist_class); x->binbuf = binbuf_new(); x->clock = clock_new(x, (t_method)qlist_tick); outlet_new(x, &s_list); outlet_new(x, &s_bang); x->onset = 0x7fffffff; x->tempo = 1; x->whenclockset = 0; x->clockdelay = 0; x->canvas = canvas_getcurrent(); x->reentered = 0; return x; } static void qlist_rewind(t_qlist *x) { x->onset = 0; if (x->clock) clock_unset(x->clock); x->whenclockset = 0; x->reentered = 1; } static void qlist_donext(t_qlist *x, int drop, int automatic) { t_pd *target = 0; while (1) { int argc = binbuf_getnatom(x->binbuf), count, onset = x->onset, onset2, wasreentered; t_atom *argv = binbuf_getvec(x->binbuf); t_atom *ap = argv + onset, *ap2; if (onset >= argc) goto end; while (ap->a_type == A_SEMI || ap->a_type == A_COMMA) { if (ap->a_type == A_SEMI) target = 0; onset++, ap++; if (onset >= argc) goto end; } if (!target && ap->a_type == A_FLOAT) { ap2 = ap + 1; onset2 = onset + 1; while (onset2 < argc && ap2->a_type == A_FLOAT) onset2++, ap2++; x->onset = onset2; if (automatic) { clock_delay(x->clock, x->clockdelay = ap->a_float * x->tempo); x->whenclockset = clock_getsystime(); } else outlet_list(x->outlet, 0, onset2-onset, ap); return; } ap2 = ap + 1; onset2 = onset + 1; while (onset2 < argc && (ap2->a_type == A_FLOAT || ap2->a_type == A_SYMBOL)) onset2++, ap2++; x->onset = onset2; count = onset2 - onset; if (!target) { if (ap->a_type != A_SYMBOL) continue; target = ap->a_symbol->thing; if (!target) {error("qlist: %s: no such object", ap->a_symbol->name); continue;} ap++; onset++; count--; if (!count) {x->onset = onset2; continue;} } wasreentered = x->reentered; x->reentered = 0; if (!drop) { if (ap->a_type == A_FLOAT) typedmess(target, &s_list, count, ap); else if (ap->a_type == A_SYMBOL) typedmess(target, ap->a_symbol, count-1, ap+1); } if (x->reentered) return; x->reentered = wasreentered; } /* while (1); never falls through */ end: x->onset = 0x7fffffff; outlet_bang(x->out(1)); x->whenclockset = 0; } static void qlist_next(t_qlist *x, t_floatarg drop) {qlist_donext(x, drop != 0, 0);} static void qlist_bang(t_qlist *x) {qlist_rewind(x); qlist_donext(x, 0, 1);} static void qlist_tick(t_qlist *x) {x->whenclockset=0; qlist_donext(x, 0, 1);} static void qlist_add(t_qlist *x, t_symbol *s, int ac, t_atom *av) { t_atom a; SETSEMI(&a); binbuf_add(x->binbuf, ac, av); binbuf_add(x->binbuf, 1, &a); } static void qlist_add2(t_qlist *x, t_symbol *s, int ac, t_atom *av) { binbuf_add(x->binbuf, ac, av); } static void qlist_clear(t_qlist *x) { qlist_rewind(x); binbuf_clear(x->binbuf); } static void qlist_set(t_qlist *x, t_symbol *s, int ac, t_atom *av) { qlist_clear(x); qlist_add(x, s, ac, av); } static void qlist_read(t_qlist *x, t_symbol *filename, t_symbol *format) { int cr = 0; if (!strcmp(format->name, "cr")) cr = 1; else if (*format->name) error("qlist_read: unknown flag: %s", format->name); if (binbuf_read_via_canvas(x->binbuf, filename->name, x->canvas, cr)) error("%s: read failed", filename->name); x->onset = 0x7fffffff; x->reentered = 1; } static void qlist_write(t_qlist *x, t_symbol *filename, t_symbol *format) { int cr = 0; char *buf = canvas_makefilename(x->canvas,filename->name,0,0); if (!strcmp(format->name, "cr")) cr = 1; else if (*format->name) error("qlist_read: unknown flag: %s", format->name); if (binbuf_write(x->binbuf, buf, "", cr)) error("%s: write failed", filename->name); free(buf); } static void qlist_print(t_qlist *x) { post("--------- textfile or qlist contents: -----------"); binbuf_print(x->binbuf); } static void qlist_tempo(t_qlist *x, t_float f) { float newtempo; if (f < 1e-20) f = 1e-20; else if (f > 1e20) f = 1e20; newtempo = 1./f; if (x->whenclockset != 0) { float elapsed = clock_gettimesince(x->whenclockset); float left = x->clockdelay - elapsed; if (left < 0) left = 0; left *= newtempo / x->tempo; clock_delay(x->clock, left); } x->tempo = newtempo; } static void qlist_free(t_qlist *x) { binbuf_free(x->binbuf); if (x->clock) clock_free(x->clock); } static t_class *textfile_class; typedef t_qlist t_textfile; static void *textfile_new() { t_textfile *x = (t_textfile *)pd_new(textfile_class); x->binbuf = binbuf_new(); outlet_new(x, &s_list); outlet_new(x, &s_bang); x->onset = 0x7fffffff; x->reentered = 0; x->tempo = 1; x->whenclockset = 0; x->clockdelay = 0; x->clock = NULL; x->canvas = canvas_getcurrent(); return x; } static void textfile_bang(t_textfile *x) { int argc = binbuf_getnatom(x->binbuf), onset = x->onset, onset2; t_atom *argv = binbuf_getvec(x->binbuf); t_atom *ap = argv + onset, *ap2; while (onset < argc && (ap->a_type == A_SEMI || ap->a_type == A_COMMA)) onset++, ap++; onset2 = onset; ap2 = ap; while (onset2 < argc && (ap2->a_type != A_SEMI && ap2->a_type != A_COMMA)) onset2++, ap2++; if (onset2 > onset) { x->onset = onset2; if (ap->a_type == A_SYMBOL) outlet_anything(x->outlet, ap->a_symbol, onset2-onset-1, ap+1); else outlet_list(x->outlet, 0, onset2-onset, ap); } else { x->onset = 0x7fffffff; outlet_bang(x->out(1)); } } static void textfile_rewind(t_qlist *x) {x->onset = 0;} static void textfile_free(t_textfile *x) {binbuf_free(x->binbuf);} extern t_pd *newest; /* the "list" object family. list append - append a list to another list prepend - prepend a list to another list split - first n elements to first outlet, rest to second outlet list trim - trim off "list" selector list length - output number of items in list Need to think more about: list foreach - spit out elements of a list one by one (also in reverse?) list array - get items from a named array as a list list reverse - permute elements of a list back to front list pack - synonym for 'pack' list unpack - synonym for 'unpack' list cat - build a list by accumulating elements Probably don't need: list first - output first n elements. list last - output last n elements list nth - nth item in list, counting from zero */ /* -------------- utility functions: storage, copying -------------- */ #if HAVE_ALLOCA #define ATOMS_ALLOCA(x, n) ((x) = (t_atom *)((n) < LIST_NGETBYTE ? \ alloca((n) * sizeof(t_atom)) : getbytes((n) * sizeof(t_atom)))) #define ATOMS_FREEA(x, n) ( \ ((n) < LIST_NGETBYTE || (free((x)), 0))) #else #define ATOMS_ALLOCA(x, n) ((x) = (t_atom *)getbytes((n) * sizeof(t_atom))) #define ATOMS_FREEA(x, n) (free((x))) #endif static void atoms_copy(int argc, t_atom *from, t_atom *to) { for (int i = 0; i < argc; i++) to[i] = from[i]; } /* ------------- fake class to divert inlets to ----------------- */ static void alist_list(t_binbuf *x, t_symbol *s, int argc, t_atom *argv) { binbuf_clear(x); x->v = (t_atom *)getbytes(argc * sizeof(*x->v)); if (!x->v) {x->n = 0; error("list_alloc: out of memory"); return;} x->n = argc; for (int i = 0; i < argc; i++) x->v[i] = argv[i]; } static void alist_anything(t_binbuf *x, t_symbol *s, int argc, t_atom *argv) { binbuf_clear(x); x->v = (t_atom *)getbytes((argc+1) * sizeof(*x->v)); if (!x->v) {x->n = 0; error("list_alloc: out of memory"); return;} x->n = argc+1; SETSYMBOL(&x->v[0], s); for (int i = 0; i < argc; i++) x->v[i+1] = argv[i]; } static void alist_toatoms(t_binbuf *x, t_atom *to) {for (size_t i=0; in; i++) to[i] = x->v[i];} t_class *list_append_class; struct t_list_append : t_object {t_binbuf *alist;}; t_class *list_prepend_class; struct t_list_prepend : t_object {t_binbuf *alist;}; t_class *list_split_class; struct t_list_split : t_object {t_float f;}; t_class *list_trim_class; struct t_list_trim : t_object {}; t_class *list_length_class; struct t_list_length : t_object {}; static t_pd *list_append_new(t_symbol *s, int argc, t_atom *argv) { t_list_append *x = (t_list_append *)pd_new(list_append_class); x->alist = binbuf_new(); alist_list(x->alist, 0, argc, argv); outlet_new(x, &s_list); inlet_new(x,x->alist, 0, 0); return x; } static t_pd *list_prepend_new(t_symbol *s, int argc, t_atom *argv) { t_list_prepend *x = (t_list_prepend *)pd_new(list_prepend_class); x->alist = binbuf_new(); alist_list(x->alist, 0, argc, argv); outlet_new(x, &s_list); inlet_new(x,x->alist,0,0); return x; } static void list_append_free (t_list_append *x) {binbuf_free(x->alist);} static void list_prepend_free(t_list_prepend *x) {binbuf_free(x->alist);} static void list_append_list(t_list_append *x, t_symbol *s, int argc, t_atom *argv) { t_atom *outv; int outc = x->alist->n + argc; ATOMS_ALLOCA(outv, outc); atoms_copy(argc, argv, outv); alist_toatoms(x->alist, outv+argc); outlet_list(x->outlet, &s_list, outc, outv); ATOMS_FREEA(outv, outc); } static void list_append_anything(t_list_append *x, t_symbol *s, int argc, t_atom *argv) { t_atom *outv; int outc = x->alist->n+argc+1; ATOMS_ALLOCA(outv, outc); SETSYMBOL(outv, s); atoms_copy(argc, argv, outv + 1); alist_toatoms(x->alist, outv + 1 + argc); outlet_list(x->outlet, &s_list, outc, outv); ATOMS_FREEA(outv, outc); } static void list_prepend_list(t_list_prepend *x, t_symbol *s, int argc, t_atom *argv) { t_atom *outv; int outc = x->alist->n + argc; ATOMS_ALLOCA(outv, outc); alist_toatoms(x->alist, outv); atoms_copy(argc, argv, outv + x->alist->n); outlet_list(x->outlet, &s_list, outc, outv); ATOMS_FREEA(outv, outc); } static void list_prepend_anything(t_list_prepend *x, t_symbol *s, int argc, t_atom *argv) { t_atom *outv; int outc = x->alist->n+argc+1; ATOMS_ALLOCA(outv, outc); alist_toatoms(x->alist, outv); SETSYMBOL(outv + x->alist->n, s); atoms_copy(argc, argv, outv + x->alist->n + 1); outlet_list(x->outlet, &s_list, outc, outv); ATOMS_FREEA(outv, outc); } static t_pd *list_split_new(t_floatarg f) { t_list_split *x = (t_list_split *)pd_new(list_split_class); outlet_new(x, &s_list); outlet_new(x, &s_list); outlet_new(x, &s_list); floatinlet_new(x, &x->f); x->f = f; return x; } static void list_split_list(t_list_split *x, t_symbol *s, int argc, t_atom *argv) { int n = (int)x->f; if (n < 0) n = 0; if (argc >= n) { outlet_list(x->out(1), &s_list, argc-n, argv+n); outlet_list(x->out(0), &s_list, n, argv); } else outlet_list(x->out(2), &s_list, argc, argv); } static void list_split_anything(t_list_split *x, t_symbol *s, int argc, t_atom *argv) { t_atom *outv; ATOMS_ALLOCA(outv, argc+1); SETSYMBOL(outv, s); atoms_copy(argc, argv, outv + 1); list_split_list(x, &s_list, argc+1, outv); ATOMS_FREEA(outv, argc+1); } static t_pd *list_trim_new() { t_list_trim *x = (t_list_trim *)pd_new(list_trim_class); outlet_new(x, &s_list); return x; } static void list_trim_list(t_list_trim *x, t_symbol *s, int argc, t_atom *argv) { if (argc < 1 || argv[0].a_type != A_SYMBOL) outlet_list(x->outlet, &s_list, argc, argv); else outlet_anything(x->outlet, argv[0].a_symbol, argc-1, argv+1); } static void list_trim_anything(t_list_trim *x, t_symbol *s, int argc, t_atom *argv) { outlet_anything(x->outlet, s, argc, argv); } static t_pd *list_length_new() { t_list_length *x = (t_list_length *)pd_new(list_length_class); outlet_new(x, &s_float); return x; } static void list_length_list( t_list_length *x, t_symbol *s, int argc, t_atom *argv) {outlet_float(x->outlet, (float)argc);} static void list_length_anything(t_list_length *x, t_symbol *s, int argc, t_atom *argv) {outlet_float(x->outlet, (float)argc+1);} static void *list_new(t_pd *dummy, t_symbol *s, int argc, t_atom *argv) { t_pd *newest = 0; /* hide global var */ if (!argc || argv[0].a_type != A_SYMBOL) newest = list_append_new(s, argc, argv); else { t_symbol *s2 = argv[0].a_symbol; if (s2 == gensym("append")) newest = list_append_new(s, argc-1, argv+1); else if (s2 == gensym("prepend")) newest = list_prepend_new(s, argc-1, argv+1); else if (s2 == gensym("split")) newest = list_split_new(atom_getfloatarg(1, argc, argv)); else if (s2 == gensym("trim")) newest = list_trim_new(); else if (s2 == gensym("length")) newest = list_length_new(); else error("list %s: unknown function", s2->name); } /* workaround for bug in kernel.c */ if (newest) pd_set_newest(newest); return newest; } #define LISTOP(name,argspec,freer) \ list_##name##_class = class_new2("list " #name,list_##name##_new,freer,sizeof(t_list_##name),0,argspec); \ class_addlist(list_##name##_class, list_##name##_list); \ class_addanything(list_##name##_class, list_##name##_anything); \ class_sethelpsymbol(list_##name##_class, &s_list); static void list_setup () { LISTOP(append,"*",list_append_free) LISTOP(prepend,"*",list_prepend_free) LISTOP(split,"F",0) LISTOP(trim,"",0) LISTOP(length,"",0) class_addcreator2("list",list_new,"*"); } /* miller's "homebrew" linear-congruential algorithm */ static t_class *random_class; struct t_random : t_object { t_float f; unsigned int state; }; static int makeseed() { static unsigned int random_nextseed = 1489853723; random_nextseed = random_nextseed * 435898247 + 938284287; return random_nextseed & 0x7fffffff; } static void *random_new(t_floatarg f) { t_random *x = (t_random *)pd_new(random_class); x->f = f; x->state = makeseed(); floatinlet_new(x,&x->f); outlet_new(x,&s_float); return x; } static void random_bang(t_random *x) { int n = (int)x->f, nval; int range = max(n,1); unsigned int randval = x->state; x->state = randval = randval * 472940017 + 832416023; nval = (int)((double)range * (double)randval * (1./4294967296.)); if (nval >= range) nval = (int)(range-1); outlet_float(x->outlet, nval); } static void random_seed(t_random *x, float f, float glob) {x->state = (int)f;} static void random_setup() { random_class = class_new2("random",random_new,0,sizeof(t_random),0,"F"); class_addbang(random_class, random_bang); class_addmethod2(random_class, random_seed,"seed","f"); } static t_class *loadbang_class; struct t_loadbang : t_object {}; static void *loadbang_new() { t_loadbang *x = (t_loadbang *)pd_new(loadbang_class); outlet_new(x,&s_bang); return x; } static void loadbang_loadbang(t_loadbang *x) { if (!sys_noloadbang) outlet_bang(x->outlet); } static void loadbang_setup() { loadbang_class = class_new2("loadbang",loadbang_new,0,sizeof(t_loadbang),CLASS_NOINLET,""); class_addmethod2(loadbang_class, loadbang_loadbang, "loadbang",""); } static t_class *namecanvas_class; struct t_namecanvas : t_object { t_symbol *sym; t_pd *owner; }; static void *namecanvas_new(t_symbol *s) { t_namecanvas *x = (t_namecanvas *)pd_new(namecanvas_class); x->owner = (t_pd *)canvas_getcurrent(); x->sym = s; if (*s->name) pd_bind(x->owner, s); return x; } static void namecanvas_free(t_namecanvas *x) { if (*x->sym->name) pd_unbind(x->owner, x->sym); } static void namecanvas_setup() { namecanvas_class = class_new2("namecanvas",namecanvas_new,namecanvas_free,sizeof(t_namecanvas),CLASS_NOINLET,"S"); } static t_class *cputime_class; struct t_cputime : t_object { #ifdef UNISTD struct tms setcputime; #endif #ifdef MSW LARGE_INTEGER kerneltime; LARGE_INTEGER usertime; bool warned; #endif }; static t_class *realtime_class; struct t_realtime : t_object {double setrealtime;}; static t_class *timer_class; struct t_timer : t_object {double settime;}; static void cputime_bang(t_cputime *x) { #ifdef UNISTD times(&x->setcputime); #endif #ifdef MSW FILETIME ignorethis, ignorethat; BOOL retval = GetProcessTimes(GetCurrentProcess(), &ignorethis, &ignorethat, (FILETIME *)&x->kerneltime, (FILETIME *)&x->usertime); if (!retval) { if (!x->warned) {error("cputime is apparently not supported on your platform"); return;} x->warned = 1; x->kerneltime.QuadPart = 0; x->usertime.QuadPart = 0; } #endif } static void cputime_bang2(t_cputime *x) { #ifdef UNISTD struct tms newcputime; times(&newcputime); float elapsedcpu = 1000 * (newcputime.tms_utime + newcputime.tms_stime - x->setcputime.tms_utime - x->setcputime.tms_stime) / HZ; #endif #ifdef MSW FILETIME ignorethis, ignorethat; LARGE_INTEGER usertime, kerneltime; BOOL retval = GetProcessTimes(GetCurrentProcess(), &ignorethis, &ignorethat, (FILETIME *)&kerneltime, (FILETIME *)&usertime); float elapsedcpu = retval ? 0.0001 * ((kerneltime.QuadPart - x->kerneltime.QuadPart) + (usertime.QuadPart - x->usertime.QuadPart)) : 0; #endif outlet_float(x->outlet, elapsedcpu); } static void realtime_bang(t_realtime *x) {x->setrealtime = sys_getrealtime();} static void timer_bang(t_timer *x ) {x->settime = clock_getsystime();} static void realtime_bang2(t_realtime *x) {outlet_float(x->outlet, (sys_getrealtime() - x->setrealtime) * 1000.);} static void timer_bang2(t_timer *x ) {outlet_float(x->outlet, clock_gettimesince(x->settime));} static void *cputime_new() { t_cputime *x = (t_cputime *)pd_new(cputime_class); outlet_new(x,gensym("float")); inlet_new(x,x,gensym("bang"),gensym("bang2")); #ifdef MSW x->warned = 0; #endif cputime_bang(x); return x; } static void *realtime_new() { t_realtime *x = (t_realtime *)pd_new(realtime_class); outlet_new(x,gensym("float")); inlet_new(x,x,gensym("bang"),gensym("bang2")); realtime_bang(x); return x; } static void *timer_new(t_floatarg f) { t_timer *x = (t_timer *)pd_new(timer_class); timer_bang(x); outlet_new(x, gensym("float")); inlet_new(x, x, gensym("bang"), gensym("bang2")); return x; } static void timer_setup() { realtime_class = class_new2("realtime",realtime_new,0,sizeof(t_realtime),0,""); cputime_class = class_new2("cputime", cputime_new, 0,sizeof(t_cputime), 0,""); timer_class = class_new2("timer", timer_new, 0,sizeof(t_timer), 0,"F"); class_addbang(realtime_class, realtime_bang); class_addbang(cputime_class, cputime_bang); class_addbang(timer_class, timer_bang); class_addmethod2(realtime_class,realtime_bang2,"bang2",""); class_addmethod2(cputime_class, cputime_bang2, "bang2",""); class_addmethod2(timer_class, timer_bang2, "bang2",""); } static t_class *print_class; struct t_print : t_object { t_symbol *sym; }; static void *print_new(t_symbol *s) { t_print *x = (t_print *)pd_new(print_class); if (*s->name) x->sym = s; else x->sym = gensym("print"); return x; } static void print_bang(t_print *x) {post("%s: bang", x->sym->name);} static void print_pointer(t_print *x, t_gpointer *gp) {post("%s: (gpointer)", x->sym->name);} static void print_float(t_print *x, t_float f) {post("%s: %g", x->sym->name, f);} static void print_list(t_print *x, t_symbol *s, int argc, t_atom *argv) { if (argc && argv->a_type != A_SYMBOL) startpost("%s:", x->sym->name); else startpost("%s: %s", x->sym->name, (argc>1 ? s_list : argc==1 ? s_symbol : s_bang).name); postatom(argc, argv); endpost(); } static void print_anything(t_print *x, t_symbol *s, int argc, t_atom *argv) { startpost("%s: %s", x->sym->name, s->name); postatom(argc, argv); endpost(); } static void print_setup() { t_class *c = print_class = class_new2("print",print_new,0,sizeof(t_print),0,"S"); class_addbang(c, print_bang); class_addfloat(c, print_float); class_addpointer(c, print_pointer); class_addlist(c, print_list); class_addanything(c, print_anything); } /*---- Macro ----*/ static t_class *macro_class; struct t_macro : t_object { t_symbol *sym; t_outlet *bangout; }; static void *macro_new(t_symbol *s) { t_macro *x = (t_macro *)pd_new(macro_class); if (*s->name) x->sym = s; else x->sym = gensym("macro"); x-> bangout = outlet_new(x, &s_bang); return x; } static void macro_bang(t_macro *x) {outlet_bang(x->bangout);} static void macro_send(t_macro *x, t_symbol *s, int argc, t_atom *argv) { std::ostringstream t; t << s->name; for (int i=0; idix->canvas, "macro_event_append", "Sp", t.str().data(), x); } static void macro_setup() { t_class *c = macro_class = class_new2("macro",macro_new,0,sizeof(t_macro),0,"S"); class_addanything(c, macro_send); class_addmethod2(c, macro_bang, "mbang",""); } /*---- Clipboard ----*/ static t_class *clipboard_class; struct t_clipboard : t_object { t_binbuf *alist; t_symbol *sym; t_outlet *dump; }; static void *clipboard_new(t_symbol *s) { t_clipboard *x = (t_clipboard *)pd_new(clipboard_class); if (*s->name) x->sym = s; else x->sym = gensym("clipboard"); x->alist = binbuf_new(); x->dump = outlet_new(x,&s_list); return x; } static void clipboard_bang(t_clipboard *x) {sys_mgui(x->dix->canvas, "get_clipboard", "p", x);} static void clipboard_reply (t_clipboard *x, t_symbol *s, int argc, t_atom *argv) { outlet_list(x->dump, &s_list, argc, argv); } static void clipboard_setup() { t_class *c = clipboard_class = class_new2("clipboard",clipboard_new,0,sizeof(t_clipboard),0,"S"); class_addbang(c, clipboard_bang); class_addmethod2(c, clipboard_reply,"clipboard_set","*"); } /*---- Display ----*/ static t_class *display_class; struct t_display : t_object { t_float height; }; static void *display_new(t_floatarg f) { t_display *x = (t_display *)pd_new(display_class); x->height = f; if (!x->height) x->height = 1; return x; } static void display_height (t_display *x) {sys_mgui(x, "height=", "i", (int)x->height);} static void display_send(t_display *x, t_symbol *s, int argc, t_atom *argv) { std::ostringstream t; t << s->name; for (int i=0; ialist = binbuf_new(); if (argc) { if (argv[0].a_type == A_FLOAT) {alist_list(x->alist, 0, argc, argv);} if (argv[0].a_type == A_SYMBOL) {alist_anything(x->alist, argv[0].a_symbol, argc-1, argv+1);} } outlet_new(x, &s_anything); inlet_new(x,x->alist, 0, 0); return x; } static void any_anything(t_any *x, t_symbol *s, int argc, t_atom *argv) { t_atom *outv; int outc = x->alist->n+argc+1; ATOMS_ALLOCA(outv, outc); if (argv[0].a_type == A_FLOAT && s->name == "list" || s->name == "float") { alist_list(x->alist, 0, argc, argv); outlet_anything(x->outlet, &s_list, argc, argv);return; } if (argv[0].a_type == A_SYMBOL || s->name != "list" || s->name != "float") { alist_anything(x->alist, s, argc, argv); outlet_anything(x->outlet, s, argc, argv); } } static void any_bang(t_any *x) { t_atom *outv; int outc = x->alist->n; ATOMS_ALLOCA(outv, outc); alist_toatoms(x->alist, outv); if (!binbuf_getnatom(x->alist)) {outlet_bang(x->outlet);return;} if (outv[0].a_type == A_FLOAT) {outlet_anything(x->outlet, &s_list, outc, outv);} if (outv[0].a_type == A_SYMBOL) {outlet_anything(x->outlet, outv[0].a_symbol, outc-1, outv+1);} ATOMS_FREEA(outv, outc); } static void any_setup() { post("DesireData iemlib2 [any] clone"); t_class *c = any_class = class_new2("any",any_new,0,sizeof(t_any),0,"*"); class_addanything(c, any_anything); class_addbang(c, any_bang); } /* MSW and OSX don't appear to have single-precision ANSI math */ #if defined(MSW) || defined(__APPLE__) #define sinf sin #define cosf cos #define atanf atan #define atan2f atan2 #define sqrtf sqrt #define logf log #define expf exp #define fabsf fabs #define powf pow #endif struct t_binop : t_object { t_float f1; t_float f2; }; static void *binop_new(t_class *floatclass, t_floatarg f) { t_binop *x = (t_binop *)pd_new(floatclass); outlet_new(x, &s_float); floatinlet_new(x, &x->f2); x->f1 = 0; x->f2 = f; return x; } #define BINOP(NAME,EXPR) \ static t_class *NAME##_class; \ static void *NAME##_new(t_floatarg f) {return binop_new(NAME##_class, f);} \ static void NAME##_bang(t_binop *x) {float a=x->f1,b=x->f2; outlet_float(x->outlet,(EXPR));} \ static void NAME##_float(t_binop *x, t_float f) {x->f1=f; NAME##_bang(x);} BINOP(binop_plus,a+b) BINOP(binop_minus,a-b) BINOP(binop_times,a*b) BINOP(binop_div,a/b) BINOP(binop_pow, a>0?powf(a,b):0) BINOP(binop_max, a>b?a:b) BINOP(binop_min, ab) BINOP(binop_lt,a=b) BINOP(binop_le,a<=b) BINOP(binop_ba,(int)a&(int)b) BINOP(binop_la,a&&b) BINOP(binop_bo,(int)a|(int)b) BINOP(binop_lo,a||b) BINOP(binop_ls,(int)a<<(int)b) BINOP(binop_rs,(int)a>>(int)b) BINOP(binop_pc,(int)a % (b?(int)b:1)) static int mymod(int a, int b) { int n2 = (int)b; if (n2 < 0) n2 = -n2; else if (!n2) n2 = 1; int r = (int)a % n2; return r<0 ? r+n2 : r; } BINOP(binop_mymod, (float)mymod((int)a,(int)b)) static int mydiv(int a, int b) { if (b < 0) b=-b; else if (!b) b=1; if (a < 0) a -= b-1; return a/b; } BINOP(binop_mydiv, (float)mydiv((int)a,(int)b)) FUNC1(sin,sinf(a)) FUNC1(cos,cosf(a)) FUNC1(tan,tanf(a)) FUNC1(atan,atanf(a)) static t_class *atan2_class; struct t_atan2 : t_object { float f; }; static void *atan2_new() { t_atan2 *x = (t_atan2 *)pd_new(atan2_class); static int warned; if (!warned) post("warning: atan2 inlets switched from Pd 0.37 to 0.38"), warned=1; floatinlet_new(x, &x->f); x->f = 0; outlet_new(x, &s_float); return x; } static void atan2_float(t_atan2 *x, t_float f) { float r = (f == 0 && x->f == 0 ? 0 : atan2f(f, x->f)); outlet_float(x->outlet, r); } FUNC1(sqrt,sqrtf(a)) FUNC1(log, a>0 ? logf(a) : -1000) FUNC1(exp,expf(min(a,87.3365f))) FUNC1(abs,fabsf(a)) static t_class *clip_class; struct t_clip : t_object { float f1; float f2; float f3; }; static void *clip_new(t_floatarg f2, t_floatarg f3) { t_clip *x = (t_clip *)pd_new(clip_class); floatinlet_new(x, &x->f2); x->f2 = f2; floatinlet_new(x, &x->f3); x->f3 = f3; outlet_new(x, &s_float); return x; } static void clip_bang( t_clip *x) { outlet_float(x->outlet, clip(x->f1,x->f2,x->f3));} static void clip_float(t_clip *x, t_float f) {x->f1 = f; outlet_float(x->outlet, clip(x->f1,x->f2,x->f3));} void arithmetic_setup() { t_symbol *s = gensym("operators"); #define BINOPDECL(NAME,SYM) \ NAME##_class = class_new2(SYM,NAME##_new,0,sizeof(t_binop),0,"F"); \ class_addbang(NAME##_class, NAME##_bang); \ class_addfloat(NAME##_class, (t_method)NAME##_float); \ class_sethelpsymbol(NAME##_class,s); BINOPDECL(binop_plus,"+") BINOPDECL(binop_minus,"-") BINOPDECL(binop_times,"*") BINOPDECL(binop_div,"/") BINOPDECL(binop_pow,"pow") BINOPDECL(binop_max,"max") BINOPDECL(binop_min,"min") s = gensym("otherbinops"); BINOPDECL(binop_ee,"==") BINOPDECL(binop_ne,"!=") BINOPDECL(binop_gt,">") BINOPDECL(binop_lt,"<") BINOPDECL(binop_ge,">=") BINOPDECL(binop_le,"<=") BINOPDECL(binop_ba,"&") BINOPDECL(binop_la,"&&") BINOPDECL(binop_bo,"|") BINOPDECL(binop_lo,"||") BINOPDECL(binop_ls,"<<") BINOPDECL(binop_rs,">>") BINOPDECL(binop_pc,"%") BINOPDECL(binop_mymod,"mod") BINOPDECL(binop_mydiv,"div") s = gensym("math"); #define FUNCDECL(NAME,SYM) \ NAME##_class = class_new2(SYM,NAME##_new,0,sizeof(t_object),0,""); \ class_addfloat(NAME##_class, (t_method)NAME##_float); \ class_sethelpsymbol(NAME##_class,s); FUNCDECL(sin,"sin"); FUNCDECL(cos,"cos"); FUNCDECL(tan,"tan"); FUNCDECL(atan,"atan"); FUNCDECL(atan2,"atan2"); /* actually a binop */ FUNCDECL(sqrt,"sqrt"); FUNCDECL(log,"log"); FUNCDECL(exp,"exp"); FUNCDECL(abs,"abs"); clip_class = class_new2("clip",clip_new,0,sizeof(t_clip),0,"FF"); class_addfloat(clip_class, clip_float); class_addbang(clip_class, clip_bang); } static t_class *pdint_class; struct t_pdint : t_object {t_float f;}; static t_class *pdfloat_class; struct t_pdfloat : t_object {t_float f;}; static t_class *pdsymbol_class; struct t_pdsymbol : t_object {t_symbol *s;}; static t_class *bang_class; struct t_bang : t_object {}; static void pdint_bang(t_pdint *x) {outlet_float(x->outlet, (t_float)(int)x->f);} static void pdint_float(t_pdint *x, t_float f) {x->f = f; pdint_bang(x);} static void pdfloat_bang(t_pdfloat *x) {outlet_float(x->outlet, x->f);} static void pdfloat_float(t_pdfloat *x, t_float f) {x->f=f; pdfloat_bang(x);} static void pdsymbol_bang(t_pdsymbol *x) {outlet_symbol(x->outlet, x->s);} static void pdsymbol_symbol( t_pdsymbol *x, t_symbol *s ) {x->s=s; pdsymbol_bang(x);} static void pdsymbol_anything(t_pdsymbol *x, t_symbol *s, int ac, t_atom *av) {x->s=s; pdsymbol_bang(x);} /* For "list" message don't just output "list"; if empty, we want to bang the symbol and if it starts with a symbol, we output that. Otherwise it's not clear what we should do so we just go for the "anything" method. LATER figure out if there are other places where empty lists aren't equivalent to "bang"??? Should Pd's message passer always check and call the more specific method, or should it be the object's responsibility? Dunno... */ #if 0 static void pdsymbol_list(t_pdsymbol *x, t_symbol *s, int ac, t_atom *av) { if (!ac) pdsymbol_bang(x); else if (av->a_type == A_SYMBOL) pdsymbol_symbol(x, av->a_symbol); else pdsymbol_anything(x, s, ac, av); } #endif static void *pdint_new(t_floatarg f) { t_pdint *x = (t_pdint *)pd_new(pdint_class); x->f = f; outlet_new(x, &s_float); floatinlet_new(x, &x->f); return x; } static void *pdfloat_new(t_pd *dummy, t_float f) { t_pdfloat *x = (t_pdfloat *)pd_new(pdfloat_class); x->f = f; outlet_new(x, &s_float); floatinlet_new(x, &x->f); pd_set_newest((t_pd *)x); return x; } static void *pdfloat_new2(t_floatarg f) {return pdfloat_new(0, f);} static void *pdsymbol_new(t_pd *dummy, t_symbol *s) { t_pdsymbol *x = (t_pdsymbol *)pd_new(pdsymbol_class); x->s = s; outlet_new(x, &s_symbol);symbolinlet_new(x, &x->s); pd_set_newest((t_pd *)x); return x; } static void *bang_new(t_pd *dummy) { t_bang *x = (t_bang *)pd_new(bang_class); outlet_new(x, &s_bang); pd_set_newest((t_pd *)x); return x; } static void *bang_new2(t_bang f) {return bang_new(0);} static void bang_bang(t_bang *x) {outlet_bang(x->outlet);} void misc_setup() { pdint_class = class_new2("int",pdint_new,0,sizeof(t_pdint),0,"F"); class_addcreator2("i",pdint_new,"F"); class_addbang(pdint_class, pdint_bang); class_addfloat(pdint_class, pdint_float); pdfloat_class = class_new2("float",pdfloat_new,0,sizeof(t_pdfloat),0,"F"); class_addcreator2("f",pdfloat_new2,"F"); class_addbang(pdfloat_class, pdfloat_bang); class_addfloat(pdfloat_class, pdfloat_float); pdsymbol_class = class_new2("symbol",pdsymbol_new,0,sizeof(t_pdsymbol),0,"S"); class_addbang(pdsymbol_class, pdsymbol_bang); class_addsymbol(pdsymbol_class, pdsymbol_symbol); class_addanything(pdsymbol_class, pdsymbol_anything); t_class *c = bang_class = class_new2("bang",bang_new,0,sizeof(t_bang),0,""); class_addcreator2("b",bang_new2,""); class_addbang(c, bang_bang); class_addfloat(c, bang_bang); class_addsymbol(c, bang_bang); class_addlist(c, bang_bang); class_addanything(c, bang_bang); } /* -------------------- send & receive ------------------------------ */ static t_class * send_class; struct t_send : t_object {t_symbol *sym;}; static t_class *receive_class; struct t_receive : t_object {t_symbol *sym;}; static void send_bang( t_send *x) { if (x->sym->thing) pd_bang(x->sym->thing);} static void send_float( t_send *x, t_float f) { if (x->sym->thing) pd_float(x->sym->thing,f);} static void send_symbol( t_send *x, t_symbol *s) { if (x->sym->thing) pd_symbol(x->sym->thing,s);} static void send_pointer( t_send *x, t_gpointer *gp) { if (x->sym->thing) pd_pointer(x->sym->thing,gp);} static void send_list( t_send *x, t_symbol *s, int argc, t_atom *argv) {if (x->sym->thing) pd_list(x->sym->thing,s,argc,argv);} static void send_anything(t_send *x, t_symbol *s, int argc, t_atom *argv) {if (x->sym->thing) typedmess(x->sym->thing,s,argc,argv);} static void receive_bang( t_receive *x) { outlet_bang(x->outlet);} static void receive_float( t_receive *x, t_float f) { outlet_float(x->outlet, f);} static void receive_symbol( t_receive *x, t_symbol *s) { outlet_symbol(x->outlet, s);} static void receive_pointer( t_receive *x, t_gpointer *gp) { outlet_pointer(x->outlet, gp);} static void receive_list( t_receive *x, t_symbol *s, int argc, t_atom *argv) { outlet_list(x->outlet, s, argc, argv);} static void receive_anything(t_receive *x, t_symbol *s, int argc, t_atom *argv) {outlet_anything(x->outlet, s, argc, argv);} static void *receive_new(t_symbol *s) { t_receive *x = (t_receive *)pd_new(receive_class); x->sym = s; pd_bind(x, s); outlet_new(x, 0); return x; } static void receive_free(t_receive *x) {pd_unbind(x, x->sym);} static void *send_new(t_symbol *s) { t_send *x = (t_send *)pd_new(send_class); if (!*s->name) symbolinlet_new(x, &x->sym); x->sym = s; return x; } static void sendreceive_setup() { t_class *c; c = send_class = class_new2("send",send_new,0,sizeof(t_send),0,"S"); class_addcreator2("s",send_new,"S"); class_addbang(c, send_bang); class_addfloat(c, send_float); class_addsymbol(c, send_symbol); class_addpointer(c, send_pointer); class_addlist(c, send_list); class_addanything(c, send_anything); c = receive_class = class_new2("receive",receive_new,receive_free,sizeof(t_receive),CLASS_NOINLET,"S"); class_addcreator2("r",receive_new,"S"); class_addbang(c, receive_bang); class_addfloat(c, receive_float); class_addsymbol(c, receive_symbol); class_addpointer(c, receive_pointer); class_addlist(c, receive_list); class_addanything(c, receive_anything); } /* -------------------------- select ------------------------------ */ static t_class *select_class; struct t_selectelement { t_atom a; t_outlet *out; }; struct t_select : t_object { t_int nelement; t_selectelement *vec; t_outlet *rejectout; }; #define select_each(e,x) for (t_selectelement *e = x->vec;e;e=0) for (int nelement = x->nelement; nelement--; e++) static void select_float(t_select *x, t_float f) { select_each(e,x) if (e->a.a_type==A_FLOAT && e->a.a_float==f) {outlet_bang(e->out); return;} outlet_float(x->rejectout, f); } static void select_symbol(t_select *x, t_symbol *s) { select_each(e,x) if (e->a.a_type==A_SYMBOL && e->a.a_symbol==s) {outlet_bang(e->out); return;} outlet_symbol(x->rejectout, s); } static void select_free(t_select *x) {free(x->vec);} static void *select_new(t_symbol *s, int argc, t_atom *argv) { t_atom a; if (argc == 0) { argc = 1; SETFLOAT(&a, 0); argv = new t_atom[1]; } t_select *x = (t_select *)pd_new(select_class); x->nelement = argc; x->vec = (t_selectelement *)getbytes(argc * sizeof(*x->vec)); t_selectelement *e = x->vec; for (int n = 0; n < argc; n++, e++) { e->out = outlet_new(x, &s_bang); e->a = argv[n]; if (e->a.a_type == A_FLOAT) floatinlet_new(x, &x->vec[n].a.a_float); else symbolinlet_new(x, &x->vec[n].a.a_symbol); } x->rejectout = outlet_new(x, &s_float); return x; } void select_setup() { select_class = class_new2("select",0,select_free,sizeof(t_select),0,""); class_addfloat(select_class, select_float); class_addsymbol(select_class, select_symbol); class_addcreator2("select",select_new,"*"); class_addcreator2("sel", select_new,"*"); } /* -------------------------- route ------------------------------ */ static t_class *route_class; struct t_routeelement { t_atom a; t_outlet *out; }; struct t_route : t_object { t_int n; t_routeelement *vec; t_outlet *rejectout; }; static void route_anything(t_route *x, t_symbol *sel, int argc, t_atom *argv) { t_routeelement *e = x->vec; post("1: sel=%s",sel->name); for (int n = x->n; n--; e++) if (e->a.a_type == A_SYMBOL) if (e->a.a_symbol == sel) { if (argc > 0 && argv[0].a_type == A_SYMBOL) outlet_anything(e->out, argv[0].a_symbol, argc-1, argv+1); else { /* tb {: avoid 1 element lists */ if (argc > 1) outlet_list(e->out, 0, argc, argv); else if (argc == 0) outlet_bang(e->out); else outlet_atom(e->out,&argv[0]); } /* tb } */ return; } outlet_anything(x->rejectout, sel, argc, argv); } #define route_eachr(E,L) for (t_routeelement *E = L->vec;E;E=0) for (int ROUTEN = x->n; ROUTEN--; E++) static void route_list(t_route *x, t_symbol *sel, int argc, t_atom *argv) { if (argc && argv->a_type == A_FLOAT) { float f = atom_getfloat(argv); route_eachr(e,x) if (e->a.a_type == A_FLOAT && e->a.a_float == f) { if (argc > 1 && argv[1].a_type == A_SYMBOL) outlet_anything(e->out, argv[1].a_symbol, argc-2, argv+2); else { argc--; argv++; if (argc > 1) outlet_list(e->out, 0, argc, argv); else if (argc == 0) outlet_bang(e->out); else outlet_atom(e->out,&argv[0]); } return; } else if (e->a.a_type == A_SYMBOL && e->a.a_symbol == &s_float) { outlet_float(e->out, argv[0].a_float); return; } } else { /* symbol arguments */ if (argc > 1) { /* 2 or more args: treat as "list" */ route_eachr(e,x) if (e->a.a_type == A_SYMBOL && e->a.a_symbol == &s_list) { if (argv[0].a_type==A_SYMBOL) outlet_anything(e->out, argv[0].a_symbol, argc-1, argv+1); else outlet_list(e->out, 0, argc, argv); return; } } else if (argc==0) {route_eachr(e,x) {if (e->a.a_symbol==&s_bang ) {outlet_bang(e->out ); return;}} } else if (argv[0].a_type==A_FLOAT) {route_eachr(e,x) {if (e->a.a_symbol==&s_float ) {outlet_atom(e->out,&argv[0]); return;}} } else if (argv[0].a_type==A_SYMBOL) {route_eachr(e,x) {if (e->a.a_symbol==&s_symbol ) {outlet_atom(e->out,&argv[0]); return;}} } else if (argv[0].a_type==A_POINTER){route_eachr(e,x) {if (e->a.a_symbol==&s_pointer) {outlet_atom(e->out,&argv[0]); return;}} } } if (!argc) outlet_bang(x->rejectout); else outlet_list(x->rejectout, 0, argc, argv); } static void route_free(t_route *x) {free(x->vec);} static void *route_new(t_symbol *s, int argc, t_atom *argv) { t_route *x = (t_route *)pd_new(route_class); if (argc == 0) { t_atom a; argc = 1; SETFLOAT(&a, 0); argv = &a; } x->n = argc; x->vec = (t_routeelement *)getbytes(argc * sizeof(*x->vec)); t_routeelement *e = x->vec; for (int n = 0; n < argc; n++, e++) { e->out = outlet_new(x, &s_list); e->a = argv[n]; } x->rejectout = outlet_new(x, &s_list); return x; } void route_setup() { route_class = class_new2("route",route_new,route_free,sizeof(t_route),0,"*"); class_addlist(route_class, route_list); class_addanything(route_class, route_anything); } static t_class *pack_class; struct t_pack : t_object { t_int n; /* number of args */ t_atom *vec; /* input values */ t_atom *outvec; /* space for output values */ }; static void *pack_new(t_symbol *s, int argc, t_atom *argv) { t_pack *x = (t_pack *)pd_new(pack_class); t_atom defarg[2], *ap, *vec, *vp; if (!argc) { argv = defarg; argc = 2; SETFLOAT(&defarg[0], 0); SETFLOAT(&defarg[1], 0); } x->n = argc; vec = x->vec = (t_atom *)getbytes(argc * sizeof(*x->vec)); x->outvec = (t_atom *)getbytes(argc * sizeof(*x->outvec)); vp = x->vec; ap = argv; for (int i = 0; i < argc; i++, ap++, vp++) { if (ap->a_type == A_FLOAT) { *vp = *ap; if (i) floatinlet_new(x, &vp->a_float); } else if (ap->a_type == A_SYMBOL) { char c = *ap->a_symbol->name; if (c == 's') { SETSYMBOL(vp, &s_symbol); if (i) symbolinlet_new(x, &vp->a_symbol);} else if (c == 'p') { /* SETPOINTER(vp, gpointer_new()) if (i) pointerinlet_new(x, gp); */} else if (c == 'f') { SETFLOAT(vp, 0); if (i) floatinlet_new(x, &vp->a_float);} else error("pack: %s: bad type '%c'", ap->a_symbol->name, c); } } outlet_new(x, &s_list); return x; } static void pack_bang(t_pack *x) { int reentered = 0, size = x->n * sizeof (t_atom); t_atom *outvec; /* reentrancy protection. The first time through use the pre-allocated outvec; if we're reentered we have to allocate new memory. */ if (!x->outvec) { outvec = (t_atom *)t_getbytes(size); reentered = 1; } else { outvec = x->outvec; x->outvec = 0; } memcpy(outvec, x->vec, size); outlet_list(x->outlet, &s_list, x->n, outvec); if (reentered) free(outvec); else x->outvec = outvec; } static void pack_pointer(t_pack *x, t_gpointer *gp) { if (x->vec->a_type == A_POINTER) { //gpointer_unset(x->gpointer); //*x->gpointer = *gp; //if (gp->o) gp->o->refcount++; pack_bang(x); } else error("pack_pointer: wrong type"); } static void pack_float(t_pack *x, t_float f) { if (x->vec->a_type == A_FLOAT ) {x->vec->a_float = f; pack_bang(x);} else error("pack_float: wrong type"); } static void pack_symbol(t_pack *x, t_symbol *s) { if (x->vec->a_type == A_SYMBOL) {x->vec->a_symbol = s; pack_bang(x);} else error("pack_symbol: wrong type"); } static void pack_list(t_pack *x, t_symbol *s, int ac, t_atom *av) {obj_list(x, 0, ac, av);} static void pack_anything(t_pack *x, t_symbol *s, int ac, t_atom *av) { t_atom *av2 = (t_atom *)getbytes((ac + 1) * sizeof(t_atom)); for (int i = 0; i < ac; i++) av2[i + 1] = av[i]; SETSYMBOL(av2, s); obj_list(x, 0, ac+1, av2); free(av2); } static void pack_free(t_pack *x) { free(x->vec); free(x->outvec); } static void pack_setup() { t_class *c = pack_class = class_new2("pack",pack_new,pack_free,sizeof(t_pack),0,"*"); class_addbang(c, pack_bang); class_addpointer(c, pack_pointer); class_addfloat(c, pack_float); class_addsymbol(c, pack_symbol); class_addlist(c, pack_list); class_addanything(c, pack_anything); } static t_class *unpack_class; struct t_unpack : t_object { t_int n; t_outlet **vec; char *vat; }; static t_atomtype atomtype_from_letter(char c) { switch (c) { case 'e': return A_ATOM; case 'f': return A_FLOAT; case 's': return A_SYMBOL; case 'p': return A_POINTER; default: return A_CANT; } } static void *unpack_new(t_symbol *s, int argc, t_atom *argv) { t_unpack *x = (t_unpack *)pd_new(unpack_class); t_atom defarg[2]; if (!argc) { argv = defarg; argc = 2; SETFLOAT(&defarg[0], 0); SETFLOAT(&defarg[1], 0); } x->n = argc; x->vec = (t_outlet **)getbytes(argc * sizeof(*x->vec)); x->vat = (char *)getbytes(argc); t_atom *ap=argv; for (int i=0; ivec[i] = outlet_new(x,0); switch (argv[i].a_type) { case A_FLOAT: x->vat[i]=A_FLOAT; break; case A_SYMBOL: { const char *s = atom_getstring(&argv[i]); if (strlen(s)<1 || (x->vat[i]=atomtype_from_letter(s[0]))==A_CANT) {error("%s: bad type", s); x->vat[i]=A_FLOAT;} break; } default: error("bad type"); } } return x; } static void unpack_list(t_unpack *x, t_symbol *s, int argc, t_atom *argv) { if (argc > x->n) argc = x->n; //for (int i=argc-1; i>=0; i--) outlet_atom(x->vec[i],&argv[i]); for (int i=argc-1; i>=0; i--) { if (x->vat[i]==A_ATOM || x->vat[i]==argv[i].a_type) outlet_atom(x->vec[i],&argv[i]); else error("type mismatch"); } } static void unpack_anything(t_unpack *x, t_symbol *s, int ac, t_atom *av) { t_atom *av2 = (t_atom *)getbytes((ac+1) * sizeof(t_atom)); for (int i=0; ivec); free(x->vat);} static void unpack_setup() { unpack_class = class_new2("unpack",unpack_new,unpack_free,sizeof(t_unpack),0,"*"); class_addlist(unpack_class, unpack_list); class_addanything(unpack_class, unpack_anything); } static t_class *trigger_class; struct t_triggerout { int type; t_outlet *outlet; }; typedef struct t_trigger : t_object { t_int n; t_triggerout *vec; }; static void *trigger_new(t_symbol *s, int argc, t_atom *argv) { t_trigger *x = (t_trigger *)pd_new(trigger_class); t_atom defarg[2]; if (!argc) { argv = defarg; argc = 2; SETSYMBOL(&defarg[0], &s_bang); SETSYMBOL(&defarg[1], &s_bang); } x->n = argc; x->vec = (t_triggerout *)getbytes(argc * sizeof(*x->vec)); t_triggerout *u = x->vec; t_atom *ap = argv; for (int i=0; ia_type; char c; if (thistype == A_SYMBOL) c = ap->a_symbol->name[0]; else if (thistype == A_FLOAT) c = 'f'; else c = 0; if (c == 'p') u->outlet = outlet_new(x, &s_pointer); else if (c == 'f') u->outlet = outlet_new(x, &s_float); else if (c == 'b') u->outlet = outlet_new(x, &s_bang); else if (c == 'l') u->outlet = outlet_new(x, &s_list); else if (c == 's') u->outlet = outlet_new(x, &s_symbol); else if (c == 'a') u->outlet = outlet_new(x, &s_symbol); else { error("trigger: %s: bad type", ap->a_symbol->name); c='f'; u->outlet = outlet_new(x, &s_float); } u->type = c; } return x; } static void trigger_list(t_trigger *x, t_symbol *s, int argc, t_atom *argv) { t_triggerout *u = x->vec+x->n; for (int i = x->n; u--, i--;) { if (u->type == 'f') outlet_float(u->outlet, argc ? atom_getfloat(argv) : 0); else if (u->type == 'b') outlet_bang(u->outlet); else if (u->type == 's') outlet_symbol(u->outlet, argc ? atom_getsymbol(argv) : &s_symbol); else if (u->type == 'p') { if (!argc || argv->a_type != 'p') error("unpack: bad pointer"); else outlet_pointer(u->outlet, argv->a_pointer); } else outlet_list(u->outlet, &s_list, argc, argv); } } static void trigger_anything(t_trigger *x, t_symbol *s, int argc, t_atom *argv) { t_triggerout *u = x->vec+x->n; for (int i = x->n; u--, i--;) { if (u->type == 'b') outlet_bang(u->outlet); else if (u->type == 'a') outlet_anything(u->outlet, s, argc, argv); else error("trigger: can only convert 's' to 'b' or 'a'", s->name); } } static void trigger_bang(t_trigger *x) {trigger_list(x, 0, 0, 0);} static void trigger_pointer(t_trigger *x, t_gpointer *gp) {t_atom at; SETPOINTER(&at, gp); trigger_list(x, 0, 1, &at);} static void trigger_float(t_trigger *x, t_float f) { t_atom at; SETFLOAT(&at, f); trigger_list(x, 0, 1, &at);} static void trigger_symbol(t_trigger *x, t_symbol *s) { t_atom at; SETSYMBOL(&at, s); trigger_list(x, 0, 1, &at);} static void trigger_free(t_trigger *x) {free(x->vec);} static void trigger_setup() { t_class *c = trigger_class = class_new2("trigger",trigger_new,trigger_free,sizeof(t_trigger),0,"*"); class_addcreator2("t",trigger_new,"*"); class_addlist(c, trigger_list); class_addbang(c, trigger_bang); class_addpointer(c, trigger_pointer); class_addfloat(c, trigger_float); class_addsymbol(c, trigger_symbol); class_addanything(c, trigger_anything); } static t_class *spigot_class; struct t_spigot : t_object {float state;}; static void *spigot_new(t_floatarg f) { t_spigot *x = (t_spigot *)pd_new(spigot_class); floatinlet_new(x, &x->state); outlet_new(x, 0); x->state = f; return x; } static void spigot_bang( t_spigot *x) { if (x->state) outlet_bang(x->outlet);} static void spigot_pointer( t_spigot *x, t_gpointer *gp) { if (x->state) outlet_pointer(x->outlet, gp);} static void spigot_float( t_spigot *x, t_float f) { if (x->state) outlet_float(x->outlet, f);} static void spigot_symbol( t_spigot *x, t_symbol *s) { if (x->state) outlet_symbol(x->outlet, s);} static void spigot_list( t_spigot *x, t_symbol *s, int argc, t_atom *argv) {if (x->state) outlet_list(x->outlet, s, argc, argv);} static void spigot_anything(t_spigot *x, t_symbol *s, int argc, t_atom *argv) {if (x->state) outlet_anything(x->outlet, s, argc, argv);} static void spigot_setup() { t_class *c = spigot_class = class_new2("spigot",spigot_new,0,sizeof(t_spigot),0,"F"); class_addbang(c, spigot_bang); class_addpointer(c, spigot_pointer); class_addfloat(c, spigot_float); class_addsymbol(c, spigot_symbol); class_addlist(c, spigot_list); class_addanything(c, spigot_anything); } static t_class *moses_class; struct t_moses : t_object {float y;}; static void *moses_new(t_floatarg f) { t_moses *x = (t_moses *)pd_new(moses_class); floatinlet_new(x, &x->y); outlet_new(x, &s_float); outlet_new(x, &s_float); x->y = f; return x; } static void moses_float(t_moses *x, t_float f) {outlet_float(x->out(f>=x->y), f);} static void moses_setup() { moses_class = class_new2("moses",moses_new,0,sizeof(t_moses),0,"F"); class_addfloat(moses_class, moses_float); } static t_class *until_class; struct t_until : t_object { int run; int count; }; static void *until_new() { t_until *x = (t_until *)pd_new(until_class); inlet_new(x, x, gensym("bang"), gensym("bang2")); outlet_new(x, &s_bang); x->run = 0; return x; } static void until_bang(t_until *x) { x->run=1; x->count=-1; while (x->run && x->count) {x->count--; outlet_bang(x->outlet);}} static void until_float(t_until *x, t_float f) {x->run=1; x->count=(int)f; while (x->run && x->count) {x->count--; outlet_bang(x->outlet);}} static void until_bang2(t_until *x) {x->run = 0;} static void until_setup() { until_class = class_new2("until",until_new,0,sizeof(t_until),0,""); class_addbang(until_class, until_bang); class_addfloat(until_class, until_float); class_addmethod2(until_class, until_bang2,"bang2",""); } static t_class *makefilename_class; struct t_makefilename : t_object {t_symbol *format;}; static void *makefilename_new(t_symbol *s) { t_makefilename *x = (t_makefilename *)pd_new(makefilename_class); if (!s->name) s = gensym("file.%d"); outlet_new(x, &s_symbol); x->format = s; return x; } /* doesn't do any typechecking or even counting the % signs properly */ static void makefilename_float(t_makefilename *x, t_floatarg f) {outlet_symbol(x->outlet,symprintf(x->format->name,(int)f));} static void makefilename_symbol(t_makefilename *x, t_symbol *s) {outlet_symbol(x->outlet,symprintf(x->format->name,s->name));} static void makefilename_set(t_makefilename *x, t_symbol *s) {x->format = s;} static void makefilename_setup() { t_class *c = makefilename_class = class_new2("makefilename",makefilename_new,0,sizeof(t_makefilename),0,"S"); class_addfloat(c, makefilename_float); class_addsymbol(c, makefilename_symbol); class_addmethod2(c, makefilename_set, "set","s"); } static t_class *swap_class; struct t_swap : t_object { t_float f1; t_float f2; }; static void *swap_new(t_floatarg f) { t_swap *x = (t_swap *)pd_new(swap_class); x->f2 = f; x->f1 = 0; outlet_new(x, &s_float); outlet_new(x, &s_float); floatinlet_new(x, &x->f2); return x; } static void swap_bang(t_swap *x) { outlet_float(x->out(1), x->f1); outlet_float(x->out(0), x->f2); } static void swap_float(t_swap *x, t_float f) { x->f1 = f; swap_bang(x); } void swap_setup() { swap_class = class_new2("swap",swap_new,0,sizeof(t_swap),0,"F"); class_addcreator2("fswap",swap_new,"F"); class_addbang(swap_class, swap_bang); class_addfloat(swap_class, swap_float); } static t_class *change_class; struct t_change : t_object {t_float f;}; static void *change_new(t_floatarg f) { t_change *x = (t_change *)pd_new(change_class); x->f = f; outlet_new(x, &s_float); return x; } static void change_bang(t_change *x) {outlet_float(x->outlet, x->f);} static void change_float(t_change *x, t_float f) { if (f != x->f) { x->f = f; outlet_float(x->outlet, x->f); } } static void change_set(t_change *x, t_float f) {x->f = f;} void change_setup() { change_class = class_new2("change",change_new,0,sizeof(t_change),0,"F"); class_addbang(change_class, change_bang); class_addfloat(change_class, change_float); class_addmethod2(change_class, change_set, "set","F"); } static t_class *value_class, *vcommon_class; struct t_vcommon : t_pd { int c_refcount; t_float f; }; typedef struct t_value : t_object { t_symbol *sym; t_float *floatstar; }; /* get a pointer to a named floating-point variable. The variable belongs to a "vcommon" object, which is created if necessary. */ t_float *value_get(t_symbol *s) { t_vcommon *c = (t_vcommon *)pd_findbyclass(s, vcommon_class); if (!c) { c = (t_vcommon *)pd_new(vcommon_class); c->f = 0; c->c_refcount = 0; pd_bind(c,s); } c->c_refcount++; return &c->f; } /* release a variable. This only frees the "vcommon" resource when the last interested party releases it. */ void value_release(t_symbol *s) { t_vcommon *c = (t_vcommon *)pd_findbyclass(s, vcommon_class); if (c) { if (!--c->c_refcount) { pd_unbind(c,s); pd_free(c); } } else bug("value_release"); } int value_getfloat(t_symbol *s, t_float *f) {t_vcommon *c=(t_vcommon *)pd_findbyclass(s,vcommon_class); if (!c) return 1; *f=c->f;return 0;} int value_setfloat(t_symbol *s, t_float f) {t_vcommon *c=(t_vcommon *)pd_findbyclass(s,vcommon_class); if (!c) return 1; c->f=f; return 0;} static void *value_new(t_symbol *s) { t_value *x = (t_value *)pd_new(value_class); x->sym = s; x->floatstar = value_get(s); outlet_new(x, &s_float); return x; } static void value_bang(t_value *x) {outlet_float(x->outlet, *x->floatstar);} static void value_float(t_value *x, t_float f) {*x->floatstar = f;} static void value_ff(t_value *x) {value_release(x->sym);} static void value_setup() { value_class = class_new2("value",value_new,value_ff,sizeof(t_value),0,"S"); class_addcreator2("v",value_new,"S"); class_addbang(value_class, value_bang); class_addfloat(value_class, value_float); vcommon_class = class_new2("value",0,0,sizeof(t_vcommon),CLASS_PD,""); } /* MIDI. */ void outmidi_noteon(int portno, int channel, int pitch, int velo); void outmidi_controlchange(int portno, int channel, int ctlno, int value); void outmidi_programchange(int portno, int channel, int value); void outmidi_pitchbend(int portno, int channel, int value); void outmidi_aftertouch(int portno, int channel, int value); void outmidi_polyaftertouch(int portno, int channel, int pitch, int value); void outmidi_mclk(int portno); static t_symbol *midiin_sym, *sysexin_sym, *notein_sym, *ctlin_sym; static t_class *midiin_class, *sysexin_class, *notein_class, *ctlin_class; struct t_midiin : t_object {}; struct t_notein : t_object {t_float ch;}; struct t_ctlin : t_object {t_float ch; t_float ctlno;}; static void midiin_list(t_midiin *x, t_symbol *s, int ac, t_atom *av) { outlet_float(x->out(1), atom_getfloatarg(1, ac, av) + 1); outlet_float(x->out(0), atom_getfloatarg(0, ac, av)); } void inmidi_byte(int portno, int byte) { if ( midiin_sym->thing) {t_atom at[2]; SETFLOAT(at, byte); SETFLOAT(at+1, portno+1); pd_list( midiin_sym->thing, 0, 2, at);} } void inmidi_sysex(int portno, int byte) { if (sysexin_sym->thing) {t_atom at[2]; SETFLOAT(at, byte); SETFLOAT(at+1, portno+1); pd_list(sysexin_sym->thing, 0, 2, at);} } static void notein_list(t_notein *x, t_symbol *s, int argc, t_atom *argv) { float pitch = atom_getfloatarg(0, argc, argv); float velo = atom_getfloatarg(1, argc, argv); float channel = atom_getfloatarg(2, argc, argv); if (x->ch) {if (channel != x->ch) return;} else outlet_float(x->out(2), channel); outlet_float(x->out(1), velo); outlet_float(x->out(0), pitch); } void inmidi_noteon(int portno, int channel, int pitch, int velo) { if (notein_sym->thing) { t_atom at[3]; SETFLOAT(at, pitch); SETFLOAT(at+1, velo); SETFLOAT(at+2, (channel + (portno << 4) + 1)); pd_list(notein_sym->thing, &s_list, 3, at); } } static void *midiin_new() { t_midiin *x = (t_midiin *)pd_new(midiin_class); outlet_new(x, &s_float); outlet_new(x, &s_float); pd_bind(x, midiin_sym); return x; } static void *sysexin_new() { t_midiin *x = (t_midiin *)pd_new(sysexin_class); outlet_new(x, &s_float); outlet_new(x, &s_float); pd_bind(x, sysexin_sym); return x; } static void *notein_new(t_floatarg f) { t_notein *x = (t_notein *)pd_new(notein_class); x->ch = f; outlet_new(x, &s_float); outlet_new(x, &s_float); if (f == 0) outlet_new(x, &s_float); pd_bind(x, notein_sym); return x; } static void *ctlin_new(t_symbol *s, int argc, t_atom *argv) { t_ctlin *x = (t_ctlin *)pd_new(ctlin_class); int ctlno = (int)(argc ? atom_getfloatarg(0, argc, argv) : -1); int channel = (int)atom_getfloatarg(1, argc, argv); x->ch = channel; x->ctlno = ctlno; outlet_new(x, &s_float); if (!channel) { if (x->ctlno < 0) outlet_new(x, &s_float); outlet_new(x, &s_float); } pd_bind(x, ctlin_sym); return x; } static void ctlin_list(t_ctlin *x, t_symbol *s, int argc, t_atom *argv) { t_float ctlnumber = atom_getfloatarg(0, argc, argv); t_float value = atom_getfloatarg(1, argc, argv); t_float channel = atom_getfloatarg(2, argc, argv); if (x->ctlno >= 0 && x->ctlno != ctlnumber) return; if (x->ch > 0 && x->ch != channel) return; if (x->ch == 0) outlet_float(x->out(2), channel); if (x->ctlno < 0) outlet_float(x->out(1), ctlnumber); outlet_float(x->out(0), value); } static void midiin_free(t_midiin *x) {pd_unbind(x, midiin_sym);} static void sysexin_free(t_midiin *x) {pd_unbind(x, sysexin_sym);} static void notein_free(t_notein *x) {pd_unbind(x, notein_sym);} static void ctlin_free(t_ctlin *x) {pd_unbind(x, ctlin_sym);} void inmidi_controlchange(int portno, int channel, int ctlnumber, int value) { if (ctlin_sym->thing) { t_atom at[3]; SETFLOAT(at, ctlnumber); SETFLOAT(at+1, value); SETFLOAT(at+2, (channel + (portno << 4) + 1)); pd_list(ctlin_sym->thing, &s_list, 3, at); } } struct t_midi2 : t_object {t_float ch;}; static void *midi2_new(t_class *cl, t_floatarg ch) { t_midi2 *x = (t_midi2 *)pd_new(cl); x->ch = ch; outlet_new(x, &s_float); if (!ch) outlet_new(x, &s_float); return x; } static void midi2_list(t_midi2 *x, t_symbol *s, int argc, t_atom *argv) { float value = atom_getfloatarg(0, argc, argv); float channel = atom_getfloatarg(1, argc, argv); if (x->ch) {if (channel != x->ch) return;} else outlet_float(x->out(1), channel); outlet_float(x->out(0), value); } static t_symbol *pgmin_sym, *bendin_sym, *touchin_sym; static t_class *pgmin_class, *bendin_class, *touchin_class; struct t_pgmin : t_midi2 {}; struct t_bendin : t_midi2 {}; struct t_touchin : t_midi2 {}; static void *pgmin_new(t_floatarg f) { t_pgmin *x = (t_pgmin *) midi2_new(pgmin_class ,f); pd_bind(x, pgmin_sym); return x;} static void *bendin_new(t_floatarg f) { t_bendin *x = (t_bendin *) midi2_new(bendin_class ,f); pd_bind(x, bendin_sym); return x;} static void *touchin_new(t_floatarg f) { t_touchin *x = (t_touchin *)midi2_new(touchin_class,f); pd_bind(x, touchin_sym); return x;} static void pgmin_free( t_pgmin *x) {pd_unbind(x, pgmin_sym);} static void bendin_free( t_bendin *x) {pd_unbind(x, bendin_sym);} static void touchin_free(t_touchin *x) {pd_unbind(x, touchin_sym);} void inmidi_programchange(int portno, int channel, int value) { if (pgmin_sym->thing) { t_atom at[2]; SETFLOAT(at,value+1); SETFLOAT(at+1, channel+(portno<<4)+1); pd_list( pgmin_sym->thing, &s_list, 2, at); } } void inmidi_pitchbend(int portno, int channel, int value) { if (bendin_sym->thing) { t_atom at[2]; SETFLOAT(at,value); SETFLOAT(at+1, channel+(portno<<4)+1); pd_list( bendin_sym->thing, &s_list, 2, at); } } void inmidi_aftertouch(int portno, int channel, int value) { if (touchin_sym->thing) { t_atom at[2]; SETFLOAT(at,value); SETFLOAT(at+1, channel+(portno<<4)+1); pd_list(touchin_sym->thing, &s_list, 2, at); } } /* ----------------------- polytouchin ------------------------- */ static t_symbol *polytouchin_sym; static t_class *polytouchin_class; struct t_polytouchin : t_object { t_float ch; }; static void *polytouchin_new(t_floatarg f) { t_polytouchin *x = (t_polytouchin *)pd_new(polytouchin_class); x->ch = f; outlet_new(x, &s_float); outlet_new(x, &s_float); if (f == 0) outlet_new(x, &s_float); pd_bind(x, polytouchin_sym); return x; } static void polytouchin_list(t_polytouchin *x, t_symbol *s, int argc, t_atom *argv) { t_float channel = atom_getfloatarg(2, argc, argv); if (x->ch) {if (channel != x->ch) return;} else outlet_float(x->out(2), channel); outlet_float(x->out(1), atom_getfloatarg(0, argc, argv)); /*pitch*/ outlet_float(x->out(0), atom_getfloatarg(1, argc, argv)); /*value*/ } static void polytouchin_free(t_polytouchin *x) {pd_unbind(x, polytouchin_sym);} static void polytouchin_setup() { polytouchin_class = class_new2("polytouchin",polytouchin_new,polytouchin_free, sizeof(t_polytouchin), CLASS_NOINLET,"F"); class_addlist(polytouchin_class, polytouchin_list); class_sethelpsymbol(polytouchin_class, gensym("midi")); polytouchin_sym = gensym("#polytouchin"); } void inmidi_polyaftertouch(int portno, int channel, int pitch, int value) { if (polytouchin_sym->thing) { t_atom at[3]; SETFLOAT(at, pitch); SETFLOAT(at+1, value); SETFLOAT(at+2, (channel + (portno << 4) + 1)); pd_list(polytouchin_sym->thing, &s_list, 3, at); } } /*----------------------- midiclkin--(midi F8 message )---------------------*/ static t_symbol *midiclkin_sym; static t_class *midiclkin_class; struct t_midiclkin : t_object {}; static void *midiclkin_new(t_floatarg f) { t_midiclkin *x = (t_midiclkin *)pd_new(midiclkin_class); outlet_new(x, &s_float); outlet_new(x, &s_float); pd_bind(x, midiclkin_sym); return x; } static void midiclkin_list(t_midiclkin *x, t_symbol *s, int argc, t_atom *argv) { outlet_float(x->out(1), atom_getfloatarg(1, argc, argv)); /*count*/ outlet_float(x->out(0), atom_getfloatarg(0, argc, argv)); /*value*/ } static void midiclkin_free(t_midiclkin *x) {pd_unbind(x, midiclkin_sym);} static void midiclkin_setup() { midiclkin_class = class_new2("midiclkin",midiclkin_new,midiclkin_free,sizeof(t_midiclkin),CLASS_NOINLET,"F"); class_addlist(midiclkin_class, midiclkin_list); class_sethelpsymbol(midiclkin_class, gensym("midi")); midiclkin_sym = gensym("#midiclkin"); } void inmidi_clk(double timing) { static float prev = 0; static float count = 0; if (midiclkin_sym->thing) { t_atom at[2]; float diff = timing - prev; count++; /* 24 count per quarter note */ if (count == 3) {SETFLOAT(at, 1); count = 0;} else SETFLOAT(at, 0); SETFLOAT(at+1, diff); pd_list(midiclkin_sym->thing, &s_list, 2, at); prev = timing; } } /*----------midirealtimein (midi FA,FB,FC,FF message)-----------------*/ static t_symbol *midirealtimein_sym; static t_class *midirealtimein_class; struct t_midirealtimein : t_object {}; static void *midirealtimein_new() { t_midirealtimein *x = (t_midirealtimein *)pd_new(midirealtimein_class); outlet_new(x, &s_float); outlet_new(x, &s_float); pd_bind(x, midirealtimein_sym); return x; } static void midirealtimein_list(t_midirealtimein *x, t_symbol *s, int argc, t_atom *argv) { outlet_float(x->out(1), atom_getfloatarg(0, argc, argv)); /*portno*/ outlet_float(x->out(0), atom_getfloatarg(1, argc, argv)); /*byte*/ } static void midirealtimein_free(t_midirealtimein *x) {pd_unbind(x, midirealtimein_sym);} static void midirealtimein_setup() { midirealtimein_class = class_new2("midirealtimein",midirealtimein_new,midirealtimein_free, sizeof(t_midirealtimein),CLASS_NOINLET,"F"); class_addlist(midirealtimein_class, midirealtimein_list); class_sethelpsymbol(midirealtimein_class, gensym("midi")); midirealtimein_sym = gensym("#midirealtimein"); } void inmidi_realtimein(int portno, int SysMsg) { if (midirealtimein_sym->thing) { t_atom at[2]; SETFLOAT(at, portno); SETFLOAT(at+1, SysMsg); pd_list(midirealtimein_sym->thing, &s_list, 2, at); } } void outmidi_byte(int portno, int byte); static t_class *midiout_class; struct t_midiout : t_object {t_float portno;}; static t_class *noteout_class; struct t_noteout : t_object {t_float v; t_float ch;}; static t_class *ctlout_class; struct t_ctlout : t_object {t_float v; t_float ch;}; static void *noteout_new(t_floatarg channel) { t_noteout *x = (t_noteout *)pd_new(noteout_class); x->v = 0; x->ch = channel<1?channel:1; floatinlet_new(x, &x->v); floatinlet_new(x, &x->ch); return x; } static void *ctlout_new(t_floatarg v, t_floatarg channel) { t_ctlout *x = (t_ctlout *)pd_new(ctlout_class); x->v = v; x->ch = channel<1?channel:1; floatinlet_new(x, &x->v); floatinlet_new(x, &x->ch); return x; } static void *midiout_new(t_floatarg portno) { t_midiout *x = (t_midiout *)pd_new(midiout_class); if (portno <= 0) portno = 1; x->portno = portno; floatinlet_new(x, &x->portno); #ifdef __irix__ post("midiout: unimplemented in IRIX"); #endif return x; } static void midiout_float(t_midiout *x, t_floatarg f){ outmidi_byte((int)x->portno-1, (int)f); } static void noteout_float(t_noteout *x, t_float f) { int binchan = max(0,(int)x->ch-1); outmidi_noteon((binchan >> 4), (binchan & 15), (int)f, (int)x->v); } static void ctlout_float(t_ctlout *x, t_float f) { int binchan = (int)x->ch - 1; if (binchan < 0) binchan = 0; outmidi_controlchange((binchan >> 4), (binchan & 15), (int)x->v, (int)f); } static t_class *pgmout_class, *bendout_class, *touchout_class; struct t_mido2 : t_object {t_float ch;}; struct t_pgmout : t_mido2 {}; struct t_bendout : t_mido2 {}; struct t_touchout : t_mido2 {}; static void *mido2_new(t_class *cl, t_floatarg channel) { t_pgmout *x = (t_pgmout *)pd_new(cl); x->ch = channel<1?channel:1; floatinlet_new(x, &x->ch); return x; } static void *pgmout_new( t_floatarg ch) {return mido2_new(pgmout_class,ch);} static void *bendout_new( t_floatarg ch) {return mido2_new(bendout_class,ch);} static void *touchout_new(t_floatarg ch) {return mido2_new(touchout_class,ch);} static void pgmout_float(t_pgmout *x, t_floatarg f) { int binchan = max(0,(int)x->ch-1); outmidi_programchange(binchan>>4, binchan&15, min(127,max(0,(int)f-1))); } static void bendout_float(t_bendout *x, t_float f) { int binchan = max(0,(int)x->ch-1); outmidi_pitchbend(binchan>>4, binchan&15, (int)f+8192); } static void touchout_float(t_touchout *x, t_float f) { int binchan = max(0,(int)x->ch-1); outmidi_aftertouch(binchan>>4, binchan&15, (int)f); } static t_class *polytouchout_class; struct t_polytouchout : t_object { t_float ch; t_float pitch; }; static void *polytouchout_new(t_floatarg channel) { t_polytouchout *x = (t_polytouchout *)pd_new(polytouchout_class); x->ch = channel<1?channel:1; x->pitch = 0; floatinlet_new(x, &x->pitch); floatinlet_new(x, &x->ch); return x; } static void polytouchout_float(t_polytouchout *x, t_float n) { int binchan = max(0,(int)x->ch-1); outmidi_polyaftertouch((binchan >> 4), (binchan & 15), (int)x->pitch, (int)n); } static void polytouchout_setup() { polytouchout_class = class_new2("polytouchout",polytouchout_new,0,sizeof(t_polytouchout),0,"F"); class_addfloat(polytouchout_class, polytouchout_float); class_sethelpsymbol(polytouchout_class, gensym("midi")); } static t_class *makenote_class; struct t_hang { t_clock *clock; t_hang *next; t_float pitch; struct t_makenote *owner; }; struct t_makenote : t_object { t_float velo; t_float dur; t_hang *hang; }; static void *makenote_new(t_floatarg velo, t_floatarg dur) { t_makenote *x = (t_makenote *)pd_new(makenote_class); x->velo = velo; x->dur = dur; floatinlet_new(x, &x->velo); floatinlet_new(x, &x->dur); outlet_new(x, &s_float); outlet_new(x, &s_float); x->hang = 0; return x; } static void makenote_tick(t_hang *hang) { t_makenote *x = hang->owner; t_hang *h2, *h3; outlet_float(x->out(1), 0); outlet_float(x->out(0), hang->pitch); if (x->hang == hang) x->hang = hang->next; else for (h2 = x->hang; (h3 = h2->next); h2 = h3) { if (h3 == hang) { h2->next = h3->next; break; } } clock_free(hang->clock); free(hang); } static void makenote_float(t_makenote *x, t_float f) { if (!x->velo) return; outlet_float(x->out(1), x->velo); outlet_float(x->out(0), f); t_hang *hang = (t_hang *)getbytes(sizeof *hang); hang->next = x->hang; x->hang = hang; hang->pitch = f; hang->owner = x; hang->clock = clock_new(hang, (t_method)makenote_tick); clock_delay(hang->clock, (x->dur >= 0 ? x->dur : 0)); } static void makenote_stop(t_makenote *x) { t_hang *hang; while ((hang = x->hang)) { outlet_float(x->out(1), 0); outlet_float(x->out(0), hang->pitch); x->hang = hang->next; clock_free(hang->clock); free(hang); } } static void makenote_clear(t_makenote *x) { t_hang *hang; while ((hang = x->hang)) { x->hang = hang->next; clock_free(hang->clock); free(hang); } } static void makenote_setup() { makenote_class = class_new2("makenote",makenote_new,makenote_clear,sizeof(t_makenote),0,"FF"); class_addfloat(makenote_class, makenote_float); class_addmethod2(makenote_class, makenote_stop, "stop",""); class_addmethod2(makenote_class, makenote_clear,"clear",""); } static t_class *stripnote_class; struct t_stripnote : t_object { t_float velo; }; static void *stripnote_new() { t_stripnote *x = (t_stripnote *)pd_new(stripnote_class); floatinlet_new(x, &x->velo); outlet_new(x, &s_float); outlet_new(x, &s_float); return x; } static void stripnote_float(t_stripnote *x, t_float f) { if (!x->velo) return; outlet_float(x->out(1), x->velo); outlet_float(x->out(0), f); } static void stripnote_setup() { stripnote_class = class_new2("stripnote",stripnote_new,0,sizeof(t_stripnote),0,""); class_addfloat(stripnote_class, stripnote_float); } static t_class *poly_class; struct t_voice { float pitch; int used; unsigned long serial; }; struct t_poly : t_object { int n; t_voice *vec; float vel; unsigned long serial; int steal; }; static void *poly_new(float fnvoice, float fsteal) { int i, n = (int)fnvoice; t_poly *x = (t_poly *)pd_new(poly_class); t_voice *v; if (n < 1) n = 1; x->n = n; x->vec = (t_voice *)getbytes(n * sizeof(*x->vec)); for (v = x->vec, i = n; i--; v++) v->pitch = v->used = v->serial = 0; x->vel = 0; x->steal = (fsteal != 0); floatinlet_new(x, &x->vel); outlet_new(x, &s_float); outlet_new(x, &s_float); outlet_new(x, &s_float); x->serial = 0; return x; } static void poly_float(t_poly *x, t_float f) { int i; t_voice *v; t_voice *firston, *firstoff; unsigned int serialon, serialoff, onindex = 0, offindex = 0; if (x->vel > 0) { /* note on. Look for a vacant voice */ for (v=x->vec, i=0, firston=firstoff=0, serialon=serialoff=0xffffffff; in; v++, i++) { if (v->used && v->serial < serialon) firston = v, serialon = v->serial, onindex = i; else if (!v->used && v->serial < serialoff) firstoff = v, serialoff = v->serial, offindex = i; } if (firstoff) { outlet_float(x->out(2), x->vel); outlet_float(x->out(1), firstoff->pitch = f); outlet_float(x->out(0), offindex+1); firstoff->used = 1; firstoff->serial = x->serial++; } /* if none, steal one */ else if (firston && x->steal) { outlet_float(x->out(2), 0); outlet_float(x->out(1), firston->pitch); outlet_float(x->out(0), onindex+1); outlet_float(x->out(2), x->vel); outlet_float(x->out(1), firston->pitch = f); outlet_float(x->out(0), onindex+1); firston->serial = x->serial++; } } else { /* note off. Turn off oldest match */ for (v = x->vec, i = 0, firston = 0, serialon = 0xffffffff; i < x->n; v++, i++) if (v->used && v->pitch == f && v->serial < serialon) firston = v, serialon = v->serial, onindex = i; if (firston) { firston->used = 0; firston->serial = x->serial++; outlet_float(x->out(2), 0); outlet_float(x->out(1), firston->pitch); outlet_float(x->out(0), onindex+1); } } } static void poly_stop(t_poly *x) { t_voice *v = x->vec; for (int i = 0; i < x->n; i++, v++) if (v->used) { outlet_float(x->out(2), 0L); outlet_float(x->out(1), v->pitch); outlet_float(x->out(0), i+1); v->used = 0; v->serial = x->serial++; } } static void poly_clear(t_poly *x) { t_voice *v = x->vec; for (int i = x->n; i--; v++) v->used = v->serial = 0; } static void poly_free(t_poly *x) {free(x->vec);} static void poly_setup() { poly_class = class_new2("poly",poly_new,poly_free,sizeof(t_poly),0,"FF"); class_addfloat(poly_class, poly_float); class_addmethod2(poly_class, poly_stop, "stop",""); class_addmethod2(poly_class, poly_clear, "clear",""); } static t_class *bag_class; struct t_bagelem { struct t_bagelem *next; t_float value; }; struct t_bag : t_object { t_float velo; t_bagelem *first; }; static void *bag_new() { t_bag *x = (t_bag *)pd_new(bag_class); x->velo = 0; floatinlet_new(x, &x->velo); outlet_new(x, &s_float); x->first = 0; return x; } static void bag_float(t_bag *x, t_float f) { t_bagelem *bagelem, *e2, *e3; if (x->velo != 0) { bagelem = (t_bagelem *)getbytes(sizeof *bagelem); bagelem->next = 0; bagelem->value = f; if (!x->first) x->first = bagelem; else { /* LATER replace with a faster algorithm */ for (e2 = x->first; (e3 = e2->next); e2 = e3) {} e2->next = bagelem; } } else { if (!x->first) return; if (x->first->value == f) { bagelem = x->first; x->first = x->first->next; free(bagelem); return; } for (e2 = x->first; (e3 = e2->next); e2 = e3) if (e3->value == f) { e2->next = e3->next; free(e3); return; } } } static void bag_flush(t_bag *x) { t_bagelem *bagelem; while ((bagelem = x->first)) { outlet_float(x->outlet, bagelem->value); x->first = bagelem->next; free(bagelem); } } static void bag_clear(t_bag *x) { t_bagelem *bagelem; while ((bagelem = x->first)) { x->first = bagelem->next; free(bagelem); } } static void bag_setup() { bag_class = class_new2("bag",bag_new,bag_clear,sizeof(t_bag),0,""); class_addfloat(bag_class, bag_float); class_addmethod2(bag_class,bag_flush,"flush",""); class_addmethod2(bag_class,bag_clear,"clear",""); } void midi_setup() { midiin_class = class_new2( "midiin", midiin_new, midiin_free,sizeof(t_midiin),CLASS_NOINLET,"F"); sysexin_class = class_new2("sysexin",sysexin_new,sysexin_free,sizeof(t_midiin),CLASS_NOINLET,"F"); notein_class = class_new2( "notein", notein_new, notein_free,sizeof(t_notein),CLASS_NOINLET,"F"); ctlin_class = class_new2( "ctlin", ctlin_new, ctlin_free,sizeof( t_ctlin),CLASS_NOINLET,"*"); class_addlist( midiin_class, midiin_list); midiin_sym = gensym( "#midiin"); class_sethelpsymbol( midiin_class, gensym("midi")); class_addlist(sysexin_class, midiin_list); sysexin_sym = gensym("#sysexin"); class_sethelpsymbol(sysexin_class, gensym("midi")); class_addlist( notein_class, notein_list); notein_sym = gensym( "#notein"); class_sethelpsymbol( notein_class, gensym("midi")); class_addlist( ctlin_class, ctlin_list); ctlin_sym = gensym( "#ctlin"); class_sethelpsymbol( ctlin_class, gensym("midi")); pgmin_class = class_new2("pgmin", pgmin_new, pgmin_free, sizeof(t_pgmin), CLASS_NOINLET,"F"); bendin_class = class_new2("bendin", bendin_new, bendin_free, sizeof(t_bendin), CLASS_NOINLET,"F"); touchin_class = class_new2("touchin",touchin_new,touchin_free,sizeof(t_touchin),CLASS_NOINLET,"F"); class_addlist( pgmin_class,midi2_list); class_addlist( bendin_class,midi2_list); class_addlist(touchin_class,midi2_list); class_sethelpsymbol( pgmin_class, gensym("midi")); class_sethelpsymbol( bendin_class, gensym("midi")); class_sethelpsymbol(touchin_class, gensym("midi")); pgmin_sym = gensym("#pgmin"); bendin_sym = gensym("#bendin"); touchin_sym = gensym("#touchin"); polytouchin_setup(); midirealtimein_setup(); midiclkin_setup(); midiout_class = class_new2("midiout", midiout_new, 0, sizeof(t_midiout), 0,"FF"); ctlout_class = class_new2("ctlout", ctlout_new, 0, sizeof(t_ctlout), 0,"FF"); noteout_class = class_new2("noteout", noteout_new, 0, sizeof(t_noteout), 0,"F"); pgmout_class = class_new2("pgmout", pgmout_new, 0, sizeof(t_pgmout), 0,"F"); bendout_class = class_new2("bendout", bendout_new, 0, sizeof(t_bendout), 0,"F"); touchout_class = class_new2("touchout", touchout_new, 0, sizeof(t_touchout), 0,"F"); class_addfloat( midiout_class, midiout_float); class_sethelpsymbol( midiout_class, gensym("midi")); class_addfloat( ctlout_class, ctlout_float); class_sethelpsymbol( ctlout_class, gensym("midi")); class_addfloat( noteout_class, noteout_float); class_sethelpsymbol( noteout_class, gensym("midi")); class_addfloat( pgmout_class, pgmout_float); class_sethelpsymbol( pgmout_class, gensym("midi")); class_addfloat( bendout_class, bendout_float); class_sethelpsymbol( bendout_class, gensym("midi")); class_addfloat(touchout_class, touchout_float); class_sethelpsymbol(touchout_class, gensym("midi")); polytouchout_setup(); makenote_setup(); stripnote_setup(); poly_setup(); bag_setup(); } static t_class *delay_class; struct t_delay : t_object { t_clock *clock; double deltime; }; static void delay_bang(t_delay *x) {clock_delay(x->clock, x->deltime);} static void delay_stop(t_delay *x) {clock_unset(x->clock);} static void delay_ft1(t_delay *x, t_floatarg g) {x->deltime = max(0.f,g);} static void delay_float(t_delay *x, t_float f) {delay_ft1(x, f); delay_bang(x);} static void delay_tick(t_delay *x) {outlet_bang(x->outlet);} static void delay_free(t_delay *x) {clock_free(x->clock);} static void *delay_new(t_floatarg f) { t_delay *x = (t_delay *)pd_new(delay_class); delay_ft1(x, f); x->clock = clock_new(x, (t_method)delay_tick); outlet_new(x, gensym("bang")); inlet_new(x, x, gensym("float"), gensym("ft1")); return x; } static void delay_setup() { t_class *c = delay_class = class_new2("delay",delay_new,delay_free,sizeof(t_delay),0,"F"); class_addcreator2("del",delay_new,"F"); class_addbang(c, delay_bang); class_addmethod2(c,delay_stop,"stop",""); class_addmethod2(c,delay_ft1,"ft1","f"); class_addfloat(c, delay_float); } static t_class *metro_class; struct t_metro : t_object { t_clock *clock; double deltime; int hit; }; static void metro_tick(t_metro *x) { x->hit = 0; outlet_bang(x->outlet); if (!x->hit) clock_delay(x->clock, x->deltime); } static void metro_float(t_metro *x, t_float f) { if (f) metro_tick(x); else clock_unset(x->clock); x->hit = 1; } static void metro_bang(t_metro *x) {metro_float(x, 1);} static void metro_stop(t_metro *x) {metro_float(x, 0);} static void metro_ft1(t_metro *x, t_floatarg g) {x->deltime = max(1.f,g);} static void metro_free(t_metro *x) {clock_free(x->clock);} static void *metro_new(t_floatarg f) { t_metro *x = (t_metro *)pd_new(metro_class); metro_ft1(x, f); x->hit = 0; x->clock = clock_new(x, (t_method)metro_tick); outlet_new(x, gensym("bang")); inlet_new(x, x, gensym("float"), gensym("ft1")); return x; } static void metro_setup() { t_class *c = metro_class = class_new2("metro",metro_new,metro_free,sizeof(t_metro),0,"F"); class_addbang(c, metro_bang); class_addmethod2(c,metro_stop,"stop",""); class_addmethod2(c,metro_ft1,"ft1","f"); class_addfloat(c, metro_float); } static t_class *line_class; struct t_line : t_object { t_clock *clock; double targettime; t_float targetval; double prevtime; t_float setval; int gotinlet; t_float grain; double oneovertimediff; double in1val; }; static void line_tick(t_line *x) { double timenow = clock_getsystime(); double msectogo = - clock_gettimesince(x->targettime); if (msectogo < 1E-9) { outlet_float(x->outlet, x->targetval); } else { outlet_float(x->outlet, x->setval + x->oneovertimediff * (timenow-x->prevtime) * (x->targetval-x->setval)); clock_delay(x->clock, (x->grain > msectogo ? msectogo : x->grain)); } } static void line_float(t_line *x, t_float f) { double timenow = clock_getsystime(); if (x->gotinlet && x->in1val > 0) { if (timenow > x->targettime) x->setval = x->targetval; else x->setval = x->setval + x->oneovertimediff * (timenow-x->prevtime) * (x->targetval-x->setval); x->prevtime = timenow; x->targettime = clock_getsystimeafter(x->in1val); x->targetval = f; line_tick(x); x->gotinlet = 0; x->oneovertimediff = 1./ (x->targettime - timenow); clock_delay(x->clock, (x->grain > x->in1val ? x->in1val : x->grain)); } else { clock_unset(x->clock); x->targetval = x->setval = f; outlet_float(x->outlet, f); } x->gotinlet = 0; } static void line_ft1(t_line *x, t_floatarg g) { x->in1val = g; x->gotinlet = 1; } static void line_stop(t_line *x) { x->targetval = x->setval; clock_unset(x->clock); } static void line_set(t_line *x, t_floatarg f) { clock_unset(x->clock); x->targetval = x->setval = f; } static void line_set_granularity(t_line *x, t_floatarg grain) { if (grain <= 0) grain = 20; x->grain = grain; } static void line_free(t_line *x) { clock_free(x->clock); } static void *line_new(t_floatarg f, t_floatarg grain) { t_line *x = (t_line *)pd_new(line_class); x->targetval = x->setval = f; x->gotinlet = 0; x->oneovertimediff = 1; x->clock = clock_new(x, (t_method)line_tick); x->targettime = x->prevtime = clock_getsystime(); line_set_granularity(x, grain); outlet_new(x, gensym("float")); inlet_new(x, x, gensym("float"), gensym("ft1")); return x; } static void line_setup() { t_class *c = line_class = class_new2("line",line_new,line_free,sizeof(t_line),0,"FF"); class_addmethod2(c,line_ft1,"ft1","f"); class_addmethod2(c,line_stop,"stop",""); class_addmethod2(c,line_set,"set","f"); class_addmethod2(c,line_set_granularity,"granularity","f"); class_addfloat(c,line_float); } static t_class *pipe_class; struct t_hang2 { t_clock *clock; t_hang2 *next; struct t_pipe *owner; union word vec[0]; /* not the actual number of elements */ }; struct t_pipe : t_object { int n; float deltime; t_atom *vec; t_hang2 *hang; }; static void *pipe_new(t_symbol *s, int argc, t_atom *argv) { t_pipe *x = (t_pipe *)pd_new(pipe_class); t_atom defarg, *ap; t_atom *vec, *vp; float deltime=0; if (argc) { if (argv[argc-1].a_type != A_FLOAT) { std::ostringstream os; atom_ostream(&argv[argc-1], os); post("pipe: %s: bad time delay value", os.str().data()); } else deltime = argv[argc-1].a_float; argc--; } if (!argc) { argv = &defarg; argc = 1; SETFLOAT(&defarg, 0); } x->n = argc; vec = x->vec = (t_atom *)getbytes(argc * sizeof(*x->vec)); vp = vec; ap = argv; for (int i=0; ia_type == A_FLOAT) { *vp = *ap; outlet_new(x, &s_float); if (i) floatinlet_new(x, &vp->a_float); } else if (ap->a_type == A_SYMBOL) { char c = *ap->a_symbol->name; if (c=='s') {SETSYMBOL(vp, &s_symbol); outlet_new(x, &s_symbol); if (i) symbolinlet_new(x, &vp->a_symbol);} else if (c=='p') {vp->a_type = A_POINTER; outlet_new(x, &s_pointer); /*if (i) pointerinlet_new(x, gp);*/} else if (c=='f') {SETFLOAT(vp,0); outlet_new(x, &s_float); if (i) floatinlet_new(x, &vp->a_float);} else error("pack: %s: bad type", ap->a_symbol->name); } } floatinlet_new(x, &x->deltime); x->hang = 0; x->deltime = deltime; return x; } static void hang_free(t_hang2 *h) { clock_free(h->clock); free(h); } static void hang_tick(t_hang2 *h) { t_pipe *x = h->owner; t_hang2 *h2, *h3; if (x->hang == h) x->hang = h->next; else for (h2 = x->hang; (h3 = h2->next); h2 = h3) { if (h3 == h) { h2->next = h3->next; break; } } t_atom *p = x->vec + x->n-1; t_word *w = h->vec + x->n-1; for (int i = x->n; i--; p--, w--) { switch (p->a_type) { case A_FLOAT: outlet_float( x->out(i), w->w_float ); break; case A_SYMBOL: outlet_symbol( x->out(i), w->w_symbol ); break; case A_POINTER:outlet_pointer(x->out(i), w->w_gpointer); break; default:{} } } hang_free(h); } static void pipe_list(t_pipe *x, t_symbol *s, int ac, t_atom *av) { t_hang2 *h = (t_hang2 *)getbytes(sizeof(*h) + (x->n - 1) * sizeof(*h->vec)); int n = x->n; if (ac > n) ac = n; t_atom *p = x->vec; t_atom *ap = av; for (int i=0; ivec; p = x->vec; for (int i=0; i< n; i++, p++, w++) *w = p->a_w; h->next = x->hang; x->hang = h; h->owner = x; h->clock = clock_new(h, (t_method)hang_tick); clock_delay(h->clock, (x->deltime >= 0 ? x->deltime : 0)); } static void pipe_flush(t_pipe *x) { while (x->hang) hang_tick(x->hang); } static void pipe_clear(t_pipe *x) { t_hang2 *hang; while ((hang = x->hang)) { x->hang = hang->next; hang_free(hang); } } static void pipe_setup() { pipe_class = class_new2("pipe",pipe_new,pipe_clear,sizeof(t_pipe),0,"*"); class_addlist(pipe_class, pipe_list); class_addmethod2(pipe_class,pipe_flush,"flush",""); class_addmethod2(pipe_class,pipe_clear,"clear",""); } /* ---------------------------------------------------------------- */ /* new desiredata classes are below this point. */ static t_class *unpost_class; struct t_unpost : t_object { t_outlet *o0,*o1; }; struct t_unpost_frame { t_unpost *self; std::ostringstream buf; }; static t_unpost_frame *current_unpost; void *unpost_new (t_symbol *s) { t_unpost *x = (t_unpost *)pd_new(unpost_class); x->o0 = outlet_new(x,&s_symbol); x->o1 = outlet_new(x,&s_symbol); return x; } extern t_printhook sys_printhook; void unpost_printhook (const char *s) { std::ostringstream &b = current_unpost->buf; b << s; char *p; const char *d=b.str().data(),*dd=d; for (;;) { p = strchr(d,'\n'); if (!p) break; outlet_symbol(current_unpost->self->o1,gensym2(d,p-d)); d=p+1; } if (d!=dd) { char *q = strdup(d); /* well i could use memmove, but i'm not supposed to use strcpy because of overlap */ current_unpost->buf.clear(); current_unpost->buf << q; free(q); } } void unpost_anything (t_unpost *x, t_symbol *s, int argc, t_atom *argv) { t_printhook backup1 = sys_printhook; t_unpost_frame *backup2 = current_unpost; sys_printhook = unpost_printhook; current_unpost = new t_unpost_frame; current_unpost->self = x; outlet_anything(x->o0,s,argc,argv); sys_printhook = backup1; current_unpost = backup2; } struct t_unparse : t_object {}; static t_class *unparse_class; void *unparse_new (t_symbol *s) { t_unparse *x = (t_unparse *)pd_new(unparse_class); outlet_new(x,&s_symbol); return x; } void unparse_list (t_unparse *x, t_symbol *s, int argc, t_atom *argv) { std::ostringstream o; for (int i=0; ioutlet,gensym(o.str().data()+1)); } struct t_parse : t_object {}; static t_class *parse_class; void *parse_new (t_symbol *s) { t_parse *x = (t_parse *)pd_new(parse_class); outlet_new(x,&s_list); return x; } void parse_symbol (t_unpost *x, t_symbol *s) { t_binbuf *b = binbuf_new(); binbuf_text(b,s->name,s->n); outlet_anything(x->outlet,&s_list,b->n,b->v); binbuf_free(b); } struct t_tracecall : t_object {}; static t_class *tracecall_class; void *tracecall_new (t_symbol *s) { t_tracecall *x = (t_tracecall *)pd_new(tracecall_class); outlet_new(x,&s_list); return x; } void tracecall_anything (t_tracecall *x, t_symbol *dummy, int dum, t_atom *my) { t_atom a[2]; for (int i=pd_stackn-1; i>=0; i--) { SETSYMBOL( &a[0],pd_stack[i].self->_class->name); SETSYMBOL( &a[1],pd_stack[i].s); //SETPOINTER(&a[2],pd_stack[i].self); outlet_list(x->outlet,&s_list,2,a); } } static void matju_setup() { unpost_class = class_new2("unpost",unpost_new,0,sizeof(t_unpost),0,""); class_addanything(unpost_class, unpost_anything); unparse_class = class_new2("unparse",unparse_new,0,sizeof(t_unparse),0,""); class_addlist(unparse_class, unparse_list); parse_class = class_new2("parse",parse_new,0,sizeof(t_parse),0,""); class_addsymbol(parse_class, parse_symbol); tracecall_class = class_new2("tracecall",tracecall_new,0,sizeof(t_tracecall),0,""); class_addanything(tracecall_class,tracecall_anything); } /* end of new desiredata classes */ /* ---------------------------------------------------------------- */ void builtins_setup() { t_symbol *s = gensym("acoustics.pd"); FUNC1DECL(mtof, "mtof"); FUNC1DECL(ftom, "ftom"); FUNC1DECL(powtodb,"powtodb"); FUNC1DECL(rmstodb,"rmstodb"); FUNC1DECL(dbtopow,"dbtopow"); FUNC1DECL(dbtorms,"dbtorms"); random_setup(); loadbang_setup(); namecanvas_setup(); print_setup(); macro_setup(); display_setup(); any_setup(); clipboard_setup(); delay_setup(); metro_setup(); line_setup(); timer_setup(); pipe_setup(); misc_setup(); sendreceive_setup(); select_setup(); route_setup(); pack_setup(); unpack_setup(); trigger_setup(); spigot_setup(); moses_setup(); until_setup(); makefilename_setup(); swap_setup(); change_setup(); value_setup(); t_class *c; qlist_class = c = class_new2("qlist",qlist_new,qlist_free,sizeof(t_qlist),0,""); class_addmethod2(c,qlist_rewind, "rewind",""); class_addmethod2(c,qlist_next, "next","F"); class_addmethod2(c,qlist_set, "set","*"); class_addmethod2(c,qlist_clear, "clear",""); class_addmethod2(c,qlist_add, "add","*"); class_addmethod2(c,qlist_add2, "add2","*"); class_addmethod2(c,qlist_add, "append","*"); class_addmethod2(c,qlist_read, "read","sS"); class_addmethod2(c,qlist_write, "write","sS"); class_addmethod2(c,qlist_print, "print","S"); class_addmethod2(c,qlist_tempo, "tempo","f"); class_addbang(c,qlist_bang); textfile_class = c = class_new2("textfile",textfile_new,textfile_free,sizeof(t_textfile),0,""); class_addmethod2(c,textfile_rewind, "rewind",""); class_addmethod2(c,qlist_set, "set","*"); class_addmethod2(c,qlist_clear, "clear",""); class_addmethod2(c,qlist_add, "add","*"); class_addmethod2(c,qlist_add2, "add2","*"); class_addmethod2(c,qlist_add, "append","*"); class_addmethod2(c,qlist_read, "read","sS"); class_addmethod2(c,qlist_write, "write","sS"); class_addmethod2(c,qlist_print, "print","S"); class_addbang(c,textfile_bang); netsend_setup(); netreceive_setup(); openpanel_setup(); savepanel_setup(); key_setup(); extern t_class *binbuf_class; class_addlist(binbuf_class, alist_list); class_addanything(binbuf_class, alist_anything); list_setup(); arithmetic_setup(); midi_setup(); matju_setup(); }