From faada59567f8cb252f4a909116595ce309ff5828 Mon Sep 17 00:00:00 2001 From: "N.N." Date: Fri, 23 May 2003 12:29:55 +0000 Subject: This commit was generated by cvs2svn to compensate for changes in r647, which included commits to RCS files with non-trunk default branches. svn path=/trunk/externals/miXed/; revision=648 --- cyclone/hammer/seq.c | 825 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 825 insertions(+) create mode 100644 cyclone/hammer/seq.c (limited to 'cyclone/hammer/seq.c') diff --git a/cyclone/hammer/seq.c b/cyclone/hammer/seq.c new file mode 100644 index 0000000..503b205 --- /dev/null +++ b/cyclone/hammer/seq.c @@ -0,0 +1,825 @@ +/* Copyright (c) 2002-2003 krzYszcz and others. + * For information on usage and redistribution, and for a DISCLAIMER OF ALL + * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ + +/* CHECKED no sharing of data among seq objects having the same creation arg */ + +#include +#include +#include +#include "m_pd.h" +#include "shared.h" +#include "common/loud.h" +#include "common/grow.h" +#include "common/sq.h" +#include "common/bifi.h" +#include "common/mifi.h" +#include "hammer/file.h" + +#define SEQ_DEBUG + +#define SEQ_INISIZE 256 /* LATER rethink */ +#define SEQ_EOM 255 /* end of message marker, LATER rethink */ + +typedef struct _seqevent +{ + int e_delta; + unsigned char e_bytes[4]; +} t_seqevent; + +typedef struct _seq +{ + t_object x_ob; + t_canvas *x_canvas; + t_symbol *x_defname; + t_hammerfile *x_filehandle; + int x_isplaying; + int x_isrecording; + int x_playhead; + float x_tempo; + double x_prevtime; + unsigned char x_status; + int x_evesize; + int x_expectedsize; + int x_size; /* as allocated */ + int x_nevents; /* as used */ + t_seqevent *x_sequence; + t_seqevent x_seqini[SEQ_INISIZE]; + t_clock *x_clock; + t_outlet *x_bangout; +} t_seq; + +static t_class *seq_class; + +static void seq_doclear(t_seq *x, int dofree) +{ + if (dofree && x->x_sequence != x->x_seqini) + { + freebytes(x->x_sequence, x->x_size * sizeof(*x->x_sequence)); + x->x_sequence = x->x_seqini; + x->x_size = SEQ_INISIZE; + } + x->x_nevents = 0; +} + +static void seq_complete(t_seq *x) +{ + if (x->x_evesize < x->x_expectedsize) + { + /* CHECKED no warning if no data after status byte requiring data */ + if (x->x_evesize > 1) + post("seq: truncated midi message"); /* CHECKED */ + /* CHECKED nothing stored */ + } + else + { + t_seqevent *ep = &x->x_sequence[x->x_nevents]; + double elapsed = clock_gettimesince(x->x_prevtime); + ep->e_delta = (int)elapsed; + x->x_prevtime = clock_getlogicaltime(); + if (x->x_evesize < 4) + ep->e_bytes[x->x_evesize] = SEQ_EOM; + x->x_nevents++; + if (x->x_nevents >= x->x_size) + { + int nexisting = x->x_size; + /* store-ahead scheme, LATER consider using x_currevent */ + int nrequested = x->x_nevents + 1; +#ifdef SEQ_DEBUG + post("growing..."); +#endif + x->x_sequence = + grow_withdata(&nrequested, &nexisting, + &x->x_size, x->x_sequence, + SEQ_INISIZE, x->x_seqini, sizeof(*x->x_sequence)); + if (nrequested <= x->x_nevents) + x->x_nevents = 0; + } + } + x->x_evesize = 0; +} + +static void seq_checkstatus(t_seq *x, unsigned char c) +{ + if (x->x_status && x->x_evesize > 1) /* LATER rethink */ + seq_complete(x); + if (c < 192) + x->x_expectedsize = 3; + else if (c < 224) + x->x_expectedsize = 2; + else if (c < 240) + x->x_expectedsize = 3; + else if (c < 248) + { + /* FIXME */ + x->x_expectedsize = -1; + } + else + { + x->x_sequence[x->x_nevents].e_bytes[0] = c; + x->x_evesize = x->x_expectedsize = 1; + seq_complete(x); + return; + } + x->x_status = x->x_sequence[x->x_nevents].e_bytes[0] = c; + x->x_evesize = 1; +} + +static void seq_addbyte(t_seq *x, unsigned char c, int docomplete) +{ + x->x_sequence[x->x_nevents].e_bytes[x->x_evesize++] = c; + if (x->x_evesize == x->x_expectedsize) + { + seq_complete(x); + if (x->x_status) + { + x->x_sequence[x->x_nevents].e_bytes[0] = x->x_status; + x->x_evesize = 1; + } + } + else if (x->x_evesize == 4) + { + if (x->x_status != 240) + bug("seq_addbyte"); + /* CHECKED sysex is broken into 4-byte packets marked with + the actual delta time of last byte received in a packet */ + seq_complete(x); + } + else if (docomplete) seq_complete(x); +} + +static void seq_endofsysex(t_seq *x) +{ + seq_addbyte(x, 247, 1); + x->x_status = 0; +} + +static void seq_stopplayback(t_seq *x) +{ + /* FIXME */ + /* CHECKED "seq: incomplete sysex" at playback stop, 247 added implicitly */ + /* CHECKME resetting controllers, etc. */ + /* CHECKED bang not sent if playback stopped early */ + clock_unset(x->x_clock); + x->x_playhead = 0; + x->x_isplaying = 0; +} + +static void seq_stoprecording(t_seq *x) +{ + if (x->x_status == 240) + { + post("seq: incomplete sysex"); /* CHECKED */ + seq_endofsysex(x); /* CHECKED 247 added implicitly */ + } + else if (x->x_status) + seq_complete(x); + /* CHECKED running status used in recording, but not across recordings */ + x->x_status = 0; + x->x_isrecording = 0; +} + +static void seq_tick(t_seq *x) +{ + if (x->x_isplaying) + { + t_seqevent *ep = &x->x_sequence[x->x_playhead++]; + unsigned char *bp = ep->e_bytes; +nextevent: + outlet_float(((t_object *)x)->ob_outlet, *bp++); + if (*bp != SEQ_EOM) + { + outlet_float(((t_object *)x)->ob_outlet, *bp++); + if (*bp != SEQ_EOM) + { + outlet_float(((t_object *)x)->ob_outlet, *bp++); + if (*bp != SEQ_EOM) + outlet_float(((t_object *)x)->ob_outlet, *bp++); + } + } + if (!x->x_isplaying) /* reentrancy protection */ + return; + if (x->x_playhead < x->x_nevents) + { + ep++; + if (ep->e_delta <= 0) + /* continue output in the same scheduler event, LATER rethink */ + { + x->x_playhead++; + bp = ep->e_bytes; + goto nextevent; + } + else clock_delay(x->x_clock, ep->e_delta); + } + else + { + seq_stopplayback(x); + /* CHECKED bang sent immediately _after_ last byte */ + outlet_bang(x->x_bangout); /* LATER think about reentrancy */ + } + } +} + +/* CHECKED running status not used in playback */ +static void seq_dostart(t_seq *x, float tempo) +{ + if (x->x_isplaying) + { + /* CHECKED tempo change */ + x->x_tempo = tempo; + /* FIXME update the clock */ + } + else + { + if (x->x_isrecording) /* CHECKED 'start' stops recording */ + seq_stoprecording(x); + /* CHECKED bang not sent if a sequence is empty */ + if (x->x_nevents) + { + x->x_tempo = tempo; + x->x_playhead = 0; + x->x_isplaying = 1; + /* playback data never sent within the scheduler event of + a start message (even for the first delta <= 0), LATER rethink */ + clock_delay(x->x_clock, x->x_sequence->e_delta); + } + } +} + +static void seq_bang(t_seq *x) +{ + seq_dostart(x, 1.0); +} + +static void seq_float(t_seq *x, t_float f) +{ + if (x->x_isrecording) + { + /* CHECKED noninteger and out of range silently truncated */ + unsigned char c = (unsigned char)f; + if (c < 128) + { + if (x->x_status) seq_addbyte(x, c, 0); + } + else if (c != 254) /* CHECKED active sensing ignored */ + { + if (x->x_status == 240) + { + if (c == 247) seq_endofsysex(x); + else + { + /* CHECKED rt bytes alike */ + post("seq: unterminated sysex"); /* CHECKED */ + seq_endofsysex(x); /* CHECKED 247 added implicitly */ + seq_checkstatus(x, c); + } + } + else if (c != 247) seq_checkstatus(x, c); + } + } +} + +static void seq_symbol(t_seq *x, t_symbol *s) +{ + loud_nomethod((t_pd *)x, &s_symbol); /* CHECKED */ +} + +static void seq_list(t_seq *x, t_symbol *s, int ac, t_atom *av) +{ + if (ac && av->a_type == A_FLOAT) seq_float(x, av->a_w.w_float); + /* CHECKED anything else/more silently ignored */ +} + +static void seq_record(t_seq *x) +{ + /* CHECKED 'record' resets recording */ + if (x->x_isplaying) /* CHECKED 'record' stops playback */ + seq_stopplayback(x); + seq_doclear(x, 0); + x->x_isrecording = 1; + x->x_prevtime = clock_getlogicaltime(); + x->x_status = 0; + x->x_evesize = 0; + x->x_expectedsize = -1; /* LATER rethink */ +} + +static void seq_append(t_seq *x) +{ + if (x->x_isrecording) + return; /* CHECKME 'append' does not reset recording */ + if (x->x_isplaying) /* CHECKME 'append' stops playback */ + seq_stopplayback(x); + x->x_isrecording = 1; + x->x_prevtime = clock_getlogicaltime(); + x->x_status = 0; + x->x_evesize = 0; + x->x_expectedsize = -1; /* LATER rethink */ +} + +static void seq_stop(t_seq *x) +{ + if (x->x_isplaying) + seq_stopplayback(x); + else if (x->x_isrecording) + seq_stoprecording(x); +} + +static int seq_dogrowing(t_seq *x, int nevents) +{ + if (nevents > x->x_size) + { + int nrequested = nevents; +#ifdef SEQ_DEBUG + post("growing..."); +#endif + x->x_sequence = + grow_nodata(&nrequested, &x->x_size, x->x_sequence, + SEQ_INISIZE, x->x_seqini, sizeof(*x->x_sequence)); + if (nrequested < nevents) + { + x->x_nevents = 0; + return (0); + } + } + x->x_nevents = nevents; + return (1); +} + +static int seq_seekhook(t_squiter *it, int offset) +{ + t_seq *x = (t_seq *)it->i_owner; + post("seek in %d", x->x_nevents); + it->i_nelems = x->x_nevents; + it->i_sequence = x->x_sequence; + if (offset < 0) + offset += it->i_nelems; + if (offset >= 0 && offset < it->i_nelems) + { + it->i_element = (t_seqevent *)it->i_sequence + offset; + it->i_index = offset; + return (1); + } + else return (0); +} + +static void seq_incrhook(t_squiter *it) +{ + ((t_seqevent *)it->i_element)++; + it->i_index++; +} + +/* LATER put seq_mfwrite_doit() functionality here */ +static void seq_getevehook(t_squiter *it, t_mifi_event *mev, int *ret) +{ + *ret = 1; +} + +static void seq_setevehook(t_squiter *it, t_mifi_event *mev, int *ret) +{ + t_seqevent *sev = it->i_element; + sev->e_delta = mev->e_delay; + sev->e_bytes[0] = mev->e_status | mev->e_channel; + sev->e_bytes[1] = mev->e_data[0]; + if (MIFI_ONE_DATABYTE(mev->e_status)) + sev->e_bytes[2] = SEQ_EOM; + else + { + sev->e_bytes[2] = mev->e_data[1]; + sev->e_bytes[3] = SEQ_EOM; + } + *ret = 1; +} + +static t_float seq_gettimhook(t_squiter *it, int *ret) +{ + t_seqevent *sev = it->i_element; + *ret = 1; + return (sev->e_delta); +} + +static void seq_settimhook(t_squiter *it, t_float f, int *ret) +{ + t_seqevent *sev = it->i_element; + sev->e_delta = f; + *ret = 1; +} + +static t_symbol *seq_gettarhook(t_squiter *it, int *ret) +{ + *ret = 1; + return (0); +} + +static void seq_settarhook(t_squiter *it, t_symbol *s, int *ret) +{ + *ret = 1; +} + +static int seq_make_iterator(t_seq *x, t_mifi_stream *stp) +{ + t_squiter *it = squiter_new(stp); + if (it) + { + it->i_owner = x; + it->i_nelems = x->x_nevents; + it->i_sequence = it->i_element = x->x_sequence; + it->i_index = 0; + it->i_hooks[SQUITER_SEEKHOOK] = (t_squiterhook)seq_seekhook; + it->i_hooks[SQUITER_INCRHOOK] = (t_squiterhook)seq_incrhook; + it->i_hooks[SQUITER_GETEVEHOOK] = (t_squiterhook)seq_getevehook; + it->i_hooks[SQUITER_SETEVEHOOK] = (t_squiterhook)seq_setevehook; + it->i_hooks[SQUITER_GETTIMHOOK] = (t_squiterhook)seq_gettimhook; + it->i_hooks[SQUITER_SETTIMHOOK] = (t_squiterhook)seq_settimhook; + it->i_hooks[SQUITER_GETTARHOOK] = (t_squiterhook)seq_gettarhook; + it->i_hooks[SQUITER_SETTARHOOK] = (t_squiterhook)seq_settarhook; + return (1); + } + else return (0); +} + +static t_mifi_stream *seq_makestream(t_seq *x) +{ + t_mifi_stream *stp = 0; + if (stp = mifi_stream_new()) + { + if (seq_make_iterator(x, stp)) + return (stp); + else + mifi_stream_free(stp); + } + return (0); +} + +static int seq_comparehook(const void *e1, const void *e2) +{ + return (((t_seqevent *)e1)->e_delta > ((t_seqevent *)e2)->e_delta ? 1 : -1); +} + +/* FIXME */ +static int seq_mfread(t_seq *x, char *path) +{ + int result = 0; + t_mifi_stream *stp = 0; + if (!(stp = seq_makestream(x)) || + !mifi_read_start(stp, path, "", 0)) + goto readfailed; +#ifdef SEQ_DEBUG + if (stp->s_nframes) + post("midifile (format %d): %d tracks, %d ticks (%d smpte frames)", + stp->s_format, stp->s_hdtracks, stp->s_nticks, stp->s_nframes); + else + post("midifile (format %d): %d tracks, %d ticks per beat", + stp->s_format, stp->s_hdtracks, stp->s_nticks); +#endif + if (mifi_read_analyse(stp) != MIFI_READ_EOF || + !seq_dogrowing(x, stp->s_nevents) || + !mifi_read_restart(stp) || + mifi_read_doit(stp) != MIFI_READ_EOF) + goto readfailed; + squmpi_sort(stp); + qsort(x->x_sequence, stp->s_nevents, sizeof(*x->x_sequence), + seq_comparehook); + sq_fold_time(stp); +#ifdef SEQ_DEBUG + post("finished reading %d events from midifile", stp->s_nevents); +#endif + result = 1; +readfailed: + if (stp) + { + mifi_read_end(stp); + mifi_stream_free(stp); + } + return (result); +} + +/* FIXME */ +static int seq_mfwrite_doit(t_seq *x, t_mifi_stream *stp) +{ + t_mifi_event *mev = stp->s_auxeve; + t_seqevent *sev = x->x_sequence; + int nevents = x->x_nevents; + while (nevents--) + { + unsigned char *bp = sev->e_bytes; + int i; + mev->e_delay = (uint32)(sev->e_delta * stp->s_timecoef); + mev->e_status = *bp & 0xf0; + mev->e_channel = *bp & 0x0f; + /* FIXME sysex continuation */ + for (i = 0, bp++; i < 3 && *bp != SEQ_EOM; i++, bp++) + mev->e_data[i] = *bp; + if (!mifi_write_event(stp, mev)) + return (0); + sev++; + } + return (1); +} + +/* FIXME */ +static int seq_mfwrite(t_seq *x, char *path) +{ + int result = 0; + t_mifi_stream *stp = 0; + if (!(stp = seq_makestream(x))) + goto writefailed; + stp->s_ntracks = 1; + stp->s_hdtracks = 1; + stp->s_format = 0; + if (!mifi_write_start(stp, path, "")) + goto writefailed; + mifi_event_settext(stp->s_auxeve, MIFI_META_TRACKNAME, "seq-track"); + if (!mifi_write_start_track(stp) || + !mifi_write_event(stp, stp->s_auxeve) || + !seq_mfwrite_doit(x, stp) || + !mifi_write_adjust_track(stp, 0)) + goto writefailed; + result = 1; +writefailed: + if (stp) + { + mifi_write_end(stp); + mifi_stream_free(stp); + } + return (result); +} + +/* FIXME */ +/* CHECKED absolute timestamps, semi-terminated, verified */ +static int seq_frombinbuf(t_seq *x, t_binbuf *bb) +{ + int nevents = 0; + int ac = binbuf_getnatom(bb); + t_atom *av = binbuf_getvec(bb); + while (ac--) + if (av++->a_type == A_SEMI) /* FIXME parsing */ + nevents++; + if (nevents) + { + t_seqevent *ep; + float prevtime = 0; + int i = -1; + if (!seq_dogrowing(x, nevents)) + return (0); + nevents = 0; + ac = binbuf_getnatom(bb); + av = binbuf_getvec(bb); + ep = x->x_sequence; + while (ac--) + { + if (av->a_type == A_FLOAT) + { + if (i < 0) + { + ep->e_delta = av->a_w.w_float - prevtime; + prevtime = av->a_w.w_float; + i = 0; + } + else if (i < 4) + ep->e_bytes[i++] = av->a_w.w_float; + /* CHECKME else */ + } + else if (av->a_type == A_SEMI && i > 0) + { + if (i < 4) + ep->e_bytes[i] = SEQ_EOM; + nevents++; + ep++; + i = -1; + } + /* CHECKME else */ + av++; + } + x->x_nevents = nevents; + } + return (nevents); +} + +static void seq_tobinbuf(t_seq *x, t_binbuf *bb) +{ + int nevents = x->x_nevents; + t_seqevent *ep = x->x_sequence; + t_atom at[5]; + float timestamp = 0; + while (nevents--) + { + unsigned char *bp = ep->e_bytes; + int i; + t_atom *ap = at; + timestamp += ep->e_delta; + SETFLOAT(ap, timestamp); /* CHECKED same for sysex continuation */ + ap++; + SETFLOAT(ap, *bp); + for (i = 0, ap++, bp++; i < 3 && *bp != SEQ_EOM; i++, ap++, bp++) + SETFLOAT(ap, *bp); + binbuf_add(bb, i + 2, at); + binbuf_addsemi(bb); + ep++; + } +} + +static void seq_textread(t_seq *x, char *path) +{ + t_binbuf *bb; + bb = binbuf_new(); + if (binbuf_read(bb, path, "", 0)) + { + /* CHECKED no complaint, open dialog presented */ + hammerpanel_open(x->x_filehandle); /* LATER rethink */ + } + else + { + int nlines = seq_frombinbuf(x, bb); + if (nlines < 0) + /* CHECKED "bad MIDI file (truncated)" alert, even if a text file */ + loud_error((t_pd *)x, "bad text file (truncated)"); + else if (nlines == 0) + { + /* CHECKED no complaint, sequence erased, LATER rethink */ + } + } + binbuf_free(bb); +} + +static void seq_textwrite(t_seq *x, char *path) +{ + t_binbuf *bb; + bb = binbuf_new(); + seq_tobinbuf(x, bb); + /* CHECKED empty sequence stored as an empty file */ + if (binbuf_write(bb, path, "", 0)) + { + /* CHECKME complaint and FIXME */ + loud_error((t_pd *)x, "error writing text file"); + } + binbuf_free(bb); +} + +static void seq_doread(t_seq *x, t_symbol *fn, int creation) +{ + char buf[MAXPDSTRING]; + if (x->x_canvas) + canvas_makefilename(x->x_canvas, fn->s_name, buf, MAXPDSTRING); + else + { + strncpy(buf, fn->s_name, MAXPDSTRING); + buf[MAXPDSTRING-1] = 0; + } + if (creation) + { + /* loading during object creation -- CHECKED no warning if a file + specified with an arg does not exist, LATER rethink */ + FILE *fp; + char path[MAXPDSTRING]; + sys_bashfilename(buf, path); + if (!(fp = fopen(path, "r"))) + return; + fclose(fp); + } + /* CHECKED all cases: arg or not, message and creation */ + post("seq: reading %s", fn->s_name); + if (!seq_mfread(x, buf)) + seq_textread(x, buf); +} + +static void seq_dowrite(t_seq *x, t_symbol *fn) +{ + char buf[MAXPDSTRING], *dotp; + if (x->x_canvas) + canvas_makefilename(x->x_canvas, fn->s_name, buf, MAXPDSTRING); + else + { + strncpy(buf, fn->s_name, MAXPDSTRING); + buf[MAXPDSTRING-1] = 0; + } + post("seq: writing %s", fn->s_name); /* CHECKED arg or not */ + /* save as text for any extension other then ".mid" */ + if ((dotp = strrchr(fn->s_name, '.')) && strcmp(dotp + 1, "mid")) + seq_textwrite(x, buf); + else /* save as mf for ".mid" or no extension at all, LATER rethink */ + seq_mfwrite(x, buf); +} + +static void seq_readhook(t_pd *z, t_symbol *fn, int ac, t_atom *av) +{ + seq_doread((t_seq *)z, fn, 0); +} + +static void seq_writehook(t_pd *z, t_symbol *fn, int ac, t_atom *av) +{ + seq_dowrite((t_seq *)z, fn); +} + +static void seq_read(t_seq *x, t_symbol *s) +{ + if (s && s != &s_) + seq_doread(x, s, 0); + else /* CHECKED no default */ + hammerpanel_open(x->x_filehandle); +} + +static void seq_write(t_seq *x, t_symbol *s) +{ + if (s && s != &s_) + seq_dowrite(x, s); + else /* CHECKED creation arg is a default */ + hammerpanel_save(x->x_filehandle, + canvas_getdir(x->x_canvas), x->x_defname); +} + +static void seq_print(t_seq *x) +{ + int nevents = x->x_nevents; + startpost("midiseq:"); /* CHECKED */ + if (nevents) + { + t_seqevent *ep = x->x_sequence; + int truncated; + if (nevents > 16) + nevents = 16, truncated = 1; + else + truncated = 0; + while (nevents--) + { + unsigned char *bp = ep->e_bytes; + int i; + if (*bp < 128 || *bp == 247) + /* CHECKED (sysex continuation) */ + startpost("\n(%d)->", ep->e_delta); + else + startpost("\n(%d)", ep->e_delta); + /* CHECKED space-separated, no semi */ + postfloat((float)*bp); + for (i = 0, bp++; i < 3 && *bp != SEQ_EOM; i++, bp++) + postfloat((float)*bp); + ep++; + } + endpost(); + if (truncated) post("..."); /* CHECKED */ + } + else post(" no sequence"); /* CHECKED */ +} + +static void seq_free(t_seq *x) +{ + if (x->x_clock) clock_free(x->x_clock); + hammerfile_free(x->x_filehandle); + if (x->x_sequence != x->x_seqini) + freebytes(x->x_sequence, x->x_size * sizeof(*x->x_sequence)); +} + +static void *seq_new(t_symbol *s) +{ + t_seq *x = (t_seq *)pd_new(seq_class); + static int warned = 0; + if (!warned) + { + loud_warning((t_pd *)x, "seq is not ready yet"); + warned = 1; + } + x->x_canvas = canvas_getcurrent(); + x->x_filehandle = hammerfile_new((t_pd *)x, 0, + seq_readhook, seq_writehook, 0); + x->x_prevtime = 0; + x->x_size = SEQ_INISIZE; + x->x_nevents = 0; + x->x_sequence = x->x_seqini; + outlet_new((t_object *)x, &s_anything); + x->x_bangout = outlet_new((t_object *)x, &s_bang); + if (s && s != &s_) + { + x->x_defname = s; /* CHECKME if 'read' changes this */ + seq_doread(x, s, 1); + } + else x->x_defname = &s_; + x->x_clock = clock_new(x, (t_method)seq_tick); + return (x); +} + +void seq_setup(void) +{ + seq_class = class_new(gensym("seq"), + (t_newmethod)seq_new, + (t_method)seq_free, + sizeof(t_seq), 0, + A_DEFSYM, 0); + class_addbang(seq_class, seq_bang); + class_addfloat(seq_class, seq_float); + /* CHECKED symbol rejected */ + class_addsymbol(seq_class, seq_symbol); + /* CHECKED 1st atom of a list accepted if a float, ignored if a symbol */ + class_addlist(seq_class, seq_list); + class_addmethod(seq_class, (t_method)seq_record, + gensym("record"), 0); + class_addmethod(seq_class, (t_method)seq_append, + gensym("append"), 0); + class_addmethod(seq_class, (t_method)seq_stop, + gensym("stop"), 0); + class_addmethod(seq_class, (t_method)seq_read, + gensym("read"), A_DEFSYM, 0); + class_addmethod(seq_class, (t_method)seq_write, + gensym("write"), A_DEFSYM, 0); + class_addmethod(seq_class, (t_method)seq_print, + gensym("print"), 0); + hammerfile_setup(seq_class, 0); +} -- cgit v1.2.1