/* Copyright (c) 2002-2005 krzYszcz and others. * For information on usage and redistribution, and for a DISCLAIMER OF ALL * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ /* CHECKME list of indices */ #include #include "m_pd.h" #include "g_canvas.h" #include "common/loud.h" #include "hammer/file.h" #include "sickle/sic.h" #define CAPTURE_DEFSIZE 4096 #define CAPTURE_DEFPRECISION 4 #define CAPTURE_MAXPRECISION 99 /* format array protection */ #define CAPTURE_MAXINDICES 4096 /* FIXME */ typedef struct _capture { t_sic x_sic; t_glist *x_glist; char x_mode; /* 'f' for first or 0 for last */ int x_precision; char x_format[8]; char *x_indices; int x_szindices; /* size of x_indices array */ int x_nindices; /* number of reported indices */ int x_nblock; float *x_buffer; int x_bufsize; int x_count; int x_head; t_hammerfile *x_filehandle; } t_capture; static t_class *capture_class; static void capture_clear(t_capture *x) { x->x_count = 0; x->x_head = 0; } static int capture_formatfloat(t_capture *x, float f, char *buf, int col, int maxcol) { char *bp = buf; int cnt = 0; if (col > 0) *bp++ = ' ', cnt++; if (x->x_precision) cnt += sprintf(bp, x->x_format, f); else cnt += sprintf(bp, "%d", (int)f); if (col + cnt > maxcol) buf[0] = '\n', col = cnt - 1; /* assuming col > 0 */ else col += cnt; return (col); } static int capture_writefloat(t_capture *x, float f, char *buf, int col, FILE *fp) { /* CHECKME linebreaks */ col = capture_formatfloat(x, f, buf, col, 80); return (fputs(buf, fp) < 0 ? -1 : col); } static void capture_dowrite(t_capture *x, t_symbol *fn) { FILE *fp = 0; int count = x->x_count; char buf[MAXPDSTRING]; canvas_makefilename(glist_getcanvas(x->x_glist), fn->s_name, buf, MAXPDSTRING); if (fp = sys_fopen(buf, "w")) /* LATER ask if overwriting, CHECKME */ { int col = 0; if (x->x_mode == 'f' || count < x->x_bufsize) { float *bp = x->x_buffer; while (count--) if ((col = capture_writefloat(x, *bp++, buf, col, fp)) < 0) goto fail; } else { float *bp = x->x_buffer + x->x_head; count = x->x_bufsize - x->x_head; while (count--) if ((col = capture_writefloat(x, *bp++, buf, col, fp)) < 0) goto fail; bp = x->x_buffer; count = x->x_head; while (count--) if ((col = capture_writefloat(x, *bp++, buf, col, fp)) < 0) goto fail; } if (col) fputc('\n', fp); fclose(fp); return; } fail: if (fp) fclose(fp); loud_syserror((t_pd *)x, 0); } static void capture_writehook(t_pd *z, t_symbol *fn, int ac, t_atom *av) { capture_dowrite((t_capture *)z, fn); } static void capture_write(t_capture *x, t_symbol *s) { if (s && s != &s_) capture_dowrite(x, s); else hammerpanel_save(x->x_filehandle, 0, 0); } static int capture_appendfloat(t_capture *x, float f, char *buf, int col, int linebreak) { /* CHECKME 80 columns */ col = capture_formatfloat(x, f, buf, col, 80); hammereditor_append(x->x_filehandle, buf); if (linebreak) { if (col) { hammereditor_append(x->x_filehandle, "\n\n"); col = 0; } else hammereditor_append(x->x_filehandle, "\n"); } return (col); } /* CHECKED blank line between blocks */ static void capture_open(t_capture *x) { int count = x->x_count; char buf[MAXPDSTRING]; int nindices = (x->x_nindices > 0 ? x->x_nindices : x->x_nblock); hammereditor_open(x->x_filehandle, "Signal Capture", ""); /* CHECKED */ if (x->x_mode == 'f' || count < x->x_bufsize) { float *bp = x->x_buffer; int col = 0, i; for (i = 1; i <= count; i++) col = capture_appendfloat(x, *bp++, buf, col, ((i % nindices) == 0)); } else { float *bp = x->x_buffer + x->x_head; int col = 0, i = x->x_bufsize; count = x->x_bufsize - x->x_head; while (count--) col = capture_appendfloat(x, *bp++, buf, col, ((--i % nindices) == 0)); bp = x->x_buffer; count = x->x_head; while (count--) col = capture_appendfloat(x, *bp++, buf, col, ((count % nindices) == 0)); } } /* CHECKED without asking and storing the changes */ static void capture_wclose(t_capture *x) { hammereditor_close(x->x_filehandle, 0); } static void capture_click(t_capture *x, t_floatarg xpos, t_floatarg ypos, t_floatarg shift, t_floatarg ctrl, t_floatarg alt) { capture_open(x); } static t_int *capture_perform_first(t_int *w) { t_capture *x = (t_capture *)(w[1]); int count = x->x_count; int bufsize = x->x_bufsize; if (count < bufsize) { t_float *in = (t_float *)(w[2]); int nblock = (int)(w[3]); float *bp = x->x_buffer + count; char *ndxp = x->x_indices; if (nblock > x->x_szindices) nblock = x->x_szindices; while (nblock--) { if (*ndxp++) { *bp++ = *in++; if (++count == bufsize) break; } else in++; } x->x_count = count; } return (w + 4); } static t_int *capture_perform_allfirst(t_int *w) { t_capture *x = (t_capture *)(w[1]); int count = x->x_count; int bufsize = x->x_bufsize; if (count < bufsize) { t_float *in = (t_float *)(w[2]); int nblock = (int)(w[3]); float *bp = x->x_buffer + count; while (nblock--) { *bp++ = *in++; if (++count == bufsize) break; } x->x_count = count; } return (w + 4); } static t_int *capture_perform_last(t_int *w) { t_capture *x = (t_capture *)(w[1]); t_float *in = (t_float *)(w[2]); int nblock = (int)(w[3]); float *buffer = x->x_buffer; int bufsize = x->x_bufsize; int count = x->x_count; int head = x->x_head; char *ndxp = x->x_indices; if (nblock > x->x_szindices) nblock = x->x_szindices; while (nblock--) { if (*ndxp++) { buffer[head++] = *in++; if (head >= bufsize) head = 0; if (count < bufsize) count++; } else in++; } x->x_count = count; x->x_head = head; return (w + 4); } static t_int *capture_perform_alllast(t_int *w) { t_capture *x = (t_capture *)(w[1]); t_float *in = (t_float *)(w[2]); int nblock = (int)(w[3]); float *buffer = x->x_buffer; int bufsize = x->x_bufsize; int count = x->x_count; int head = x->x_head; while (nblock--) { buffer[head++] = *in++; if (head >= bufsize) head = 0; if (count < bufsize) count++; } x->x_count = count; x->x_head = head; return (w + 4); } static void capture_dsp(t_capture *x, t_signal **sp) { x->x_nblock = sp[0]->s_n; if (x->x_indices) dsp_add((x->x_mode == 'f' ? capture_perform_first : capture_perform_last), 3, x, sp[0]->s_vec, sp[0]->s_n); else dsp_add((x->x_mode == 'f' ? capture_perform_allfirst : capture_perform_alllast), 3, x, sp[0]->s_vec, sp[0]->s_n); } static void capture_free(t_capture *x) { hammerfile_free(x->x_filehandle); if (x->x_indices) freebytes(x->x_indices, x->x_szindices * sizeof(*x->x_indices)); if (x->x_buffer) freebytes(x->x_buffer, x->x_bufsize * sizeof(*x->x_buffer)); } static void *capture_new(t_symbol *s, int ac, t_atom *av) { t_capture *x = 0; char mode = 0; int precision = -1; float *buffer; int bufsize = 0; char *indices = 0; int szindices = 0, nindices = -1; if (ac && av->a_type == A_SYMBOL) { t_symbol *s = av->a_w.w_symbol; if (s && *s->s_name == 'f') /* CHECKME */ mode = 'f'; ac--; av++; } if (ac && av->a_type == A_FLOAT) { bufsize = (int)av->a_w.w_float; /* CHECKME */ ac--; av++; if (ac && av->a_type == A_FLOAT) { int i; t_atom *ap; precision = (int)av->a_w.w_float; /* CHECKME */ ac--; av++; for (i = 0, ap = av; i < ac; i++, ap++) { if (ap->a_type == A_FLOAT) { int ndx = (int)ap->a_w.w_float; /* CHECKME noninteger, negative */ ndx++; if (ndx >= CAPTURE_MAXINDICES) { /* CHECKME complaint */ szindices = CAPTURE_MAXINDICES; break; } else if (ndx > szindices) szindices = ndx; } else break; /* CHECKME */ } if (szindices && (indices = getbytes(szindices * sizeof(*indices)))) { nindices = 0; while (i--) { int ndx = (int)av++->a_w.w_float; /* CHECKME noninteger */ if (ndx >= 0 && ndx < szindices) indices[ndx] = 1, nindices++; } } } } if (bufsize <= 0) /* CHECKME */ bufsize = CAPTURE_DEFSIZE; if (buffer = getbytes(bufsize * sizeof(*buffer))) { x = (t_capture *)pd_new(capture_class); x->x_glist = canvas_getcurrent(); x->x_mode = mode; if (precision < 0) /* CHECKME */ precision = CAPTURE_DEFPRECISION; else if (precision > CAPTURE_MAXPRECISION) /* CHECKME */ precision = CAPTURE_MAXPRECISION; if (x->x_precision = precision) sprintf(x->x_format, "%%.%dg", precision); x->x_indices = indices; x->x_szindices = szindices; x->x_nindices = nindices; x->x_nblock = 64; /* redundant */ x->x_buffer = buffer; x->x_bufsize = bufsize; x->x_filehandle = hammerfile_new((t_pd *)x, 0, 0, capture_writehook, 0); capture_clear(x); } else if (indices) freebytes(indices, szindices * sizeof(*indices)); return (x); } void capture_tilde_setup(void) { capture_class = class_new(gensym("capture~"), (t_newmethod)capture_new, (t_method)capture_free, sizeof(t_capture), 0, A_GIMME, 0); sic_setup(capture_class, capture_dsp, SIC_FLOATTOSIGNAL); class_addmethod(capture_class, (t_method)capture_clear, gensym("clear"), 0); class_addmethod(capture_class, (t_method)capture_write, gensym("write"), A_DEFSYM, 0); class_addmethod(capture_class, (t_method)capture_open, gensym("open"), 0); class_addmethod(capture_class, (t_method)capture_wclose, gensym("wclose"), 0); class_addmethod(capture_class, (t_method)capture_click, gensym("click"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0); hammerfile_setup(capture_class, 0); }