diff --git a/pd/src/s_main.c b/pd/src/s_main.c index 38d79fa729b13c7fe34006d2d908e9abc98412f2..c6c48eee353b775d12cfcd159adfbf63a20c2080 100644 --- a/pd/src/s_main.c +++ b/pd/src/s_main.c @@ -106,7 +106,7 @@ t_sample* get_sys_soundin() { return sys_soundin; } int* get_sys_main_advance() { return &sys_main_advance; } double* get_sys_time_per_dsp_tick() { return &sys_time_per_dsp_tick; } int* get_sys_schedblocksize() { return &sys_schedblocksize; } -double* get_sys_time() { return &sys_time; } +double* get_sys_time() { return &pd_this->pd_systime; } t_float* get_sys_dacsr() { return &sys_dacsr; } int* get_sys_sleepgrain() { return &sys_sleepgrain; } int* get_sys_schedadvance() { return &sys_schedadvance; } diff --git a/pd/src/s_path.c b/pd/src/s_path.c index 659609d664b347174cf011e29c3d02ed762eb6d1..7d028d8c88b64626c1ed42b2ca9e7ed492268a83 100644 --- a/pd/src/s_path.c +++ b/pd/src/s_path.c @@ -40,8 +40,10 @@ t_namelist *sys_externlist; t_namelist *sys_searchpath; +t_namelist *sys_staticpath; t_namelist *sys_helppath; + /* change '/' characters to the system's native file separator */ void sys_bashfilename(const char *from, char *to) { @@ -297,9 +299,12 @@ void sys_setextrapath(const char *p) namelist_free(pd_extrapath); /* add standard place for users to install stuff first */ #ifdef __gnu_linux__ - sys_expandpath("~/pd-l2ork-externals", pathbuf); + sys_expandpath("~/.local/lib/pd-l2ork/extra/", pathbuf); pd_extrapath = namelist_append(0, pathbuf, 0); - pd_extrapath = namelist_append(pd_extrapath, "/usr/local/lib/pd-l2ork-externals", 0); + sys_expandpath("~/pd-l2ork-externals", pathbuf); + pd_extrapath = namelist_append(pd_extrapath, pathbuf, 0); + pd_extrapath = namelist_append(pd_extrapath, + "/usr/local/lib/pd-l2ork-externals", 0); #endif #ifdef __APPLE__ @@ -309,9 +314,9 @@ void sys_setextrapath(const char *p) #endif #ifdef _WIN32 - sys_expandpath("%ProgramFiles%/Common Files/Pd", pathbuf); + sys_expandpath("%AppData%/Pd", pathbuf); pd_extrapath = namelist_append(0, pathbuf, 0); - sys_expandpath("%UserProfile%/Application Data/Pd", pathbuf); + sys_expandpath("%CommonProgramFiles%/Pd", pathbuf); pd_extrapath = namelist_append(pd_extrapath, pathbuf, 0); #endif /* add built-in "extra" path last so its checked last */ @@ -468,6 +473,94 @@ int open_via_path(const char *dir, const char *name, const char *ext, size, bin, sys_searchpath)); } + /* open a file with a UTF-8 filename + This is needed because WIN32 does not support UTF-8 filenames, only UCS2. + Having this function prevents lots of #ifdefs all over the place. + */ +#ifdef _WIN32 +int sys_open(const char *path, int oflag, ...) +{ + int i, fd; + char pathbuf[MAXPDSTRING]; + wchar_t ucs2path[MAXPDSTRING]; + sys_bashfilename(path, pathbuf); + u8_utf8toucs2(ucs2path, MAXPDSTRING, pathbuf, MAXPDSTRING-1); + /* For the create mode, Win32 does not have the same possibilities, + * so we ignore the argument and just hard-code read/write. */ + if (oflag & O_CREAT) + fd = _wopen(ucs2path, oflag | O_BINARY, _S_IREAD | _S_IWRITE); + else + fd = _wopen(ucs2path, oflag | O_BINARY); + return fd; +} + +FILE *sys_fopen(const char *filename, const char *mode) +{ + char namebuf[MAXPDSTRING]; + wchar_t ucs2buf[MAXPDSTRING]; + wchar_t ucs2mode[MAXPDSTRING]; + sys_bashfilename(filename, namebuf); + u8_utf8toucs2(ucs2buf, MAXPDSTRING, namebuf, MAXPDSTRING-1); + /* mode only uses ASCII, so no need for a full conversion, just copy it */ + mbstowcs(ucs2mode, mode, MAXPDSTRING); + return (_wfopen(ucs2buf, ucs2mode)); +} +#else +#include <stdarg.h> +int sys_open(const char *path, int oflag, ...) +{ + int i, fd; + char pathbuf[MAXPDSTRING]; + sys_bashfilename(path, pathbuf); + if (oflag & O_CREAT) + { + mode_t mode; + int imode; + va_list ap; + va_start(ap, oflag); + + /* Mac compiler complains if we just set mode = va_arg ... so, even + though we all know it's just an int, we explicitly va_arg to an int + and then convert. + -> http://www.mail-archive.com/bug-gnulib@gnu.org/msg14212.html + -> http://bugs.debian.org/647345 + */ + + imode = va_arg (ap, int); + mode = (mode_t)imode; + va_end(ap); + fd = open(pathbuf, oflag, mode); + } + else + fd = open(pathbuf, oflag); + return fd; +} + +FILE *sys_fopen(const char *filename, const char *mode) +{ + char namebuf[MAXPDSTRING]; + sys_bashfilename(filename, namebuf); + return fopen(namebuf, mode); +} +#endif /* _WIN32 */ + + /* close a previously opened file + this is needed on platforms where you cannot open/close resources + across dll-boundaries, but we provide it for other platforms as well */ +int sys_close(int fd) +{ +#ifdef _WIN32 + return _close(fd); /* Bill Gates is a big fat hen */ +#else + return close(fd); +#endif +} + +int sys_fclose(FILE *stream) +{ + return fclose(stream); +} + /* Open a help file using the help search path. We expect the ".pd" suffix here, even though we have to tear it back off for one of the search attempts. */ diff --git a/pd/src/x_midi.c b/pd/src/x_midi.c index b43abe7219184145bc84b6df5b2f60631c32a88c..443295d54d1c7596b39bed73f0b8296f76d03f53 100644 --- a/pd/src/x_midi.c +++ b/pd/src/x_midi.c @@ -5,6 +5,7 @@ /* MIDI. */ #include "m_pd.h" +#include "m_imp.h" 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); @@ -17,8 +18,6 @@ void outmidi_byte(int portno, int value); /* ----------------------- midiin and sysexin ------------------------- */ -static t_symbol *midiin_sym, *sysexin_sym; - static t_class *midiin_class, *sysexin_class; typedef struct _midiin @@ -33,10 +32,7 @@ static void *midiin_new( void) t_midiin *x = (t_midiin *)pd_new(midiin_class); x->x_outlet1 = outlet_new(&x->x_obj, &s_float); x->x_outlet2 = outlet_new(&x->x_obj, &s_float); - pd_bind(&x->x_obj.ob_pd, midiin_sym); -#ifdef WIN32 - pd_error(x, "midiin: windows: not supported"); -#endif + pd_bind(&x->x_obj.ob_pd, pd_this->pd_midiin_sym); return (x); } @@ -48,7 +44,7 @@ static void midiin_list(t_midiin *x, t_symbol *s, int ac, t_atom *av) static void midiin_free(t_midiin *x) { - pd_unbind(&x->x_obj.ob_pd, midiin_sym); + pd_unbind(&x->x_obj.ob_pd, pd_this->pd_midiin_sym); } static void *sysexin_new( void) @@ -56,16 +52,13 @@ static void *sysexin_new( void) t_midiin *x = (t_midiin *)pd_new(sysexin_class); x->x_outlet1 = outlet_new(&x->x_obj, &s_float); x->x_outlet2 = outlet_new(&x->x_obj, &s_float); - pd_bind(&x->x_obj.ob_pd, sysexin_sym); -#ifdef WIN32 - pd_error(x, "sysexin: windows: not supported"); -#endif + pd_bind(&x->x_obj.ob_pd, pd_this->pd_sysexin_sym); return (x); } static void sysexin_free(t_midiin *x) { - pd_unbind(&x->x_obj.ob_pd, sysexin_sym); + pd_unbind(&x->x_obj.ob_pd, pd_this->pd_sysexin_sym); } static void midiin_setup(void) @@ -75,42 +68,38 @@ static void midiin_setup(void) CLASS_NOINLET, A_DEFFLOAT, 0); class_addlist(midiin_class, midiin_list); class_sethelpsymbol(midiin_class, gensym("midi")); - midiin_sym = gensym("#midiin"); sysexin_class = class_new(gensym("sysexin"), (t_newmethod)sysexin_new, (t_method)sysexin_free, sizeof(t_midiin), CLASS_NOINLET, A_DEFFLOAT, 0); class_addlist(sysexin_class, midiin_list); class_sethelpsymbol(sysexin_class, gensym("midi")); - sysexin_sym = gensym("#sysexin"); } void inmidi_byte(int portno, int byte) { t_atom at[2]; - if (midiin_sym->s_thing) + if (pd_this->pd_midiin_sym->s_thing) { SETFLOAT(at, byte); - SETFLOAT(at+1, portno + 1); - pd_list(midiin_sym->s_thing, 0, 2, at); + SETFLOAT(at+1, portno); + pd_list(pd_this->pd_midiin_sym->s_thing, 0, 2, at); } } void inmidi_sysex(int portno, int byte) { t_atom at[2]; - if (sysexin_sym->s_thing) + if (pd_this->pd_sysexin_sym->s_thing) { SETFLOAT(at, byte); - SETFLOAT(at+1, portno + 1); - pd_list(sysexin_sym->s_thing, 0, 2, at); + SETFLOAT(at+1, portno); + pd_list(pd_this->pd_sysexin_sym->s_thing, 0, 2, at); } } /* ----------------------- notein ------------------------- */ -static t_symbol *notein_sym; - static t_class *notein_class; typedef struct _notein @@ -129,7 +118,7 @@ static void *notein_new(t_floatarg f) x->x_outlet1 = outlet_new(&x->x_obj, &s_float); x->x_outlet2 = outlet_new(&x->x_obj, &s_float); if (f == 0) x->x_outlet3 = outlet_new(&x->x_obj, &s_float); - pd_bind(&x->x_obj.ob_pd, notein_sym); + pd_bind(&x->x_obj.ob_pd, pd_this->pd_notein_sym); return (x); } @@ -154,7 +143,7 @@ static void notein_list(t_notein *x, t_symbol *s, int argc, t_atom *argv) static void notein_free(t_notein *x) { - pd_unbind(&x->x_obj.ob_pd, notein_sym); + pd_unbind(&x->x_obj.ob_pd, pd_this->pd_notein_sym); } static void notein_setup(void) @@ -162,25 +151,23 @@ static void notein_setup(void) notein_class = class_new(gensym("notein"), (t_newmethod)notein_new, (t_method)notein_free, sizeof(t_notein), CLASS_NOINLET, A_DEFFLOAT, 0); class_addlist(notein_class, notein_list); - notein_sym = gensym("#notein"); + class_sethelpsymbol(notein_class, gensym("midi")); } void inmidi_noteon(int portno, int channel, int pitch, int velo) { - if (notein_sym->s_thing) + if (pd_this->pd_notein_sym->s_thing) { t_atom at[3]; SETFLOAT(at, pitch); SETFLOAT(at+1, velo); SETFLOAT(at+2, (channel + (portno << 4) + 1)); - pd_list(notein_sym->s_thing, &s_list, 3, at); + pd_list(pd_this->pd_notein_sym->s_thing, &s_list, 3, at); } } /* ----------------------- ctlin ------------------------- */ -static t_symbol *ctlin_sym; - static t_class *ctlin_class; typedef struct _ctlin @@ -208,7 +195,7 @@ static void *ctlin_new(t_symbol *s, int argc, t_atom *argv) if (x->x_ctlno < 0) x->x_outlet2 = outlet_new(&x->x_obj, &s_float); x->x_outlet3 = outlet_new(&x->x_obj, &s_float); } - pd_bind(&x->x_obj.ob_pd, ctlin_sym); + pd_bind(&x->x_obj.ob_pd, pd_this->pd_ctlin_sym); return (x); } @@ -226,34 +213,32 @@ static void ctlin_list(t_ctlin *x, t_symbol *s, int argc, t_atom *argv) static void ctlin_free(t_ctlin *x) { - pd_unbind(&x->x_obj.ob_pd, ctlin_sym); + pd_unbind(&x->x_obj.ob_pd, pd_this->pd_ctlin_sym); } static void ctlin_setup(void) { - ctlin_class = class_new(gensym("ctlin"), (t_newmethod)ctlin_new, + ctlin_class = class_new(gensym("ctlin"), (t_newmethod)ctlin_new, (t_method)ctlin_free, sizeof(t_ctlin), CLASS_NOINLET, A_GIMME, 0); class_addlist(ctlin_class, ctlin_list); - ctlin_sym = gensym("#ctlin"); + class_sethelpsymbol(ctlin_class, gensym("midi")); } void inmidi_controlchange(int portno, int channel, int ctlnumber, int value) { - if (ctlin_sym->s_thing) + if (pd_this->pd_ctlin_sym->s_thing) { t_atom at[3]; SETFLOAT(at, ctlnumber); SETFLOAT(at+1, value); SETFLOAT(at+2, (channel + (portno << 4) + 1)); - pd_list(ctlin_sym->s_thing, &s_list, 3, at); + pd_list(pd_this->pd_ctlin_sym->s_thing, &s_list, 3, at); } } /* ----------------------- pgmin ------------------------- */ -static t_symbol *pgmin_sym; - static t_class *pgmin_class; typedef struct _pgmin @@ -270,7 +255,7 @@ static void *pgmin_new(t_floatarg f) x->x_channel = f; x->x_outlet1 = outlet_new(&x->x_obj, &s_float); if (f == 0) x->x_outlet2 = outlet_new(&x->x_obj, &s_float); - pd_bind(&x->x_obj.ob_pd, pgmin_sym); + pd_bind(&x->x_obj.ob_pd, pd_this->pd_pgmin_sym); return (x); } @@ -292,7 +277,7 @@ static void pgmin_list(t_pgmin *x, t_symbol *s, int argc, t_atom *argv) static void pgmin_free(t_pgmin *x) { - pd_unbind(&x->x_obj.ob_pd, pgmin_sym); + pd_unbind(&x->x_obj.ob_pd, pd_this->pd_pgmin_sym); } static void pgmin_setup(void) @@ -301,24 +286,22 @@ static void pgmin_setup(void) (t_method)pgmin_free, sizeof(t_pgmin), CLASS_NOINLET, A_DEFFLOAT, 0); class_addlist(pgmin_class, pgmin_list); - pgmin_sym = gensym("#pgmin"); + class_sethelpsymbol(pgmin_class, gensym("midi")); } void inmidi_programchange(int portno, int channel, int value) { - if (pgmin_sym->s_thing) + if (pd_this->pd_pgmin_sym->s_thing) { t_atom at[2]; SETFLOAT(at, value + 1); SETFLOAT(at+1, (channel + (portno << 4) + 1)); - pd_list(pgmin_sym->s_thing, &s_list, 2, at); + pd_list(pd_this->pd_pgmin_sym->s_thing, &s_list, 2, at); } } /* ----------------------- bendin ------------------------- */ -static t_symbol *bendin_sym; - static t_class *bendin_class; typedef struct _bendin @@ -335,7 +318,7 @@ static void *bendin_new(t_floatarg f) x->x_channel = f; x->x_outlet1 = outlet_new(&x->x_obj, &s_float); if (f == 0) x->x_outlet2 = outlet_new(&x->x_obj, &s_float); - pd_bind(&x->x_obj.ob_pd, bendin_sym); + pd_bind(&x->x_obj.ob_pd, pd_this->pd_bendin_sym); return (x); } @@ -357,7 +340,7 @@ static void bendin_list(t_bendin *x, t_symbol *s, int argc, t_atom *argv) static void bendin_free(t_bendin *x) { - pd_unbind(&x->x_obj.ob_pd, bendin_sym); + pd_unbind(&x->x_obj.ob_pd, pd_this->pd_bendin_sym); } static void bendin_setup(void) @@ -365,24 +348,22 @@ static void bendin_setup(void) bendin_class = class_new(gensym("bendin"), (t_newmethod)bendin_new, (t_method)bendin_free, sizeof(t_bendin), CLASS_NOINLET, A_DEFFLOAT, 0); class_addlist(bendin_class, bendin_list); - bendin_sym = gensym("#bendin"); + class_sethelpsymbol(bendin_class, gensym("midi")); } void inmidi_pitchbend(int portno, int channel, int value) { - if (bendin_sym->s_thing) + if (pd_this->pd_bendin_sym->s_thing) { t_atom at[2]; SETFLOAT(at, value); SETFLOAT(at+1, (channel + (portno << 4) + 1)); - pd_list(bendin_sym->s_thing, &s_list, 2, at); + pd_list(pd_this->pd_bendin_sym->s_thing, &s_list, 2, at); } } /* ----------------------- touchin ------------------------- */ -static t_symbol *touchin_sym; - static t_class *touchin_class; typedef struct _touchin @@ -399,7 +380,7 @@ static void *touchin_new(t_floatarg f) x->x_channel = f; x->x_outlet1 = outlet_new(&x->x_obj, &s_float); if (f == 0) x->x_outlet2 = outlet_new(&x->x_obj, &s_float); - pd_bind(&x->x_obj.ob_pd, touchin_sym); + pd_bind(&x->x_obj.ob_pd, pd_this->pd_touchin_sym); return (x); } @@ -421,7 +402,7 @@ static void touchin_list(t_touchin *x, t_symbol *s, int argc, t_atom *argv) static void touchin_free(t_touchin *x) { - pd_unbind(&x->x_obj.ob_pd, touchin_sym); + pd_unbind(&x->x_obj.ob_pd, pd_this->pd_touchin_sym); } static void touchin_setup(void) @@ -431,24 +412,21 @@ static void touchin_setup(void) CLASS_NOINLET, A_DEFFLOAT, 0); class_addlist(touchin_class, touchin_list); class_sethelpsymbol(touchin_class, gensym("midi")); - touchin_sym = gensym("#touchin"); } void inmidi_aftertouch(int portno, int channel, int value) { - if (touchin_sym->s_thing) + if (pd_this->pd_touchin_sym->s_thing) { t_atom at[2]; SETFLOAT(at, value); SETFLOAT(at+1, (channel + (portno << 4) + 1)); - pd_list(touchin_sym->s_thing, &s_list, 2, at); + pd_list(pd_this->pd_touchin_sym->s_thing, &s_list, 2, at); } } /* ----------------------- polytouchin ------------------------- */ -static t_symbol *polytouchin_sym; - static t_class *polytouchin_class; typedef struct _polytouchin @@ -467,7 +445,7 @@ static void *polytouchin_new(t_floatarg f) x->x_outlet1 = outlet_new(&x->x_obj, &s_float); x->x_outlet2 = outlet_new(&x->x_obj, &s_float); if (f == 0) x->x_outlet3 = outlet_new(&x->x_obj, &s_float); - pd_bind(&x->x_obj.ob_pd, polytouchin_sym); + pd_bind(&x->x_obj.ob_pd, pd_this->pd_polytouchin_sym); return (x); } @@ -493,7 +471,7 @@ static void polytouchin_list(t_polytouchin *x, t_symbol *s, int argc, static void polytouchin_free(t_polytouchin *x) { - pd_unbind(&x->x_obj.ob_pd, polytouchin_sym); + pd_unbind(&x->x_obj.ob_pd, pd_this->pd_polytouchin_sym); } static void polytouchin_setup(void) @@ -503,27 +481,24 @@ static void polytouchin_setup(void) sizeof(t_polytouchin), CLASS_NOINLET, A_DEFFLOAT, 0); 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->s_thing) + if (pd_this->pd_polytouchin_sym->s_thing) { t_atom at[3]; SETFLOAT(at, pitch); SETFLOAT(at+1, value); SETFLOAT(at+2, (channel + (portno << 4) + 1)); - pd_list(polytouchin_sym->s_thing, &s_list, 3, at); + pd_list(pd_this->pd_polytouchin_sym->s_thing, &s_list, 3, at); } } /*----------------------- midiclkin--(midi F8 message )---------------------*/ -static t_symbol *midiclkin_sym; static t_class *midiclkin_class; - typedef struct _midiclkin { t_object x_obj; @@ -536,7 +511,7 @@ static void *midiclkin_new(t_floatarg f) t_midiclkin *x = (t_midiclkin *)pd_new(midiclkin_class); x->x_outlet1 = outlet_new(&x->x_obj, &s_float); x->x_outlet2 = outlet_new(&x->x_obj, &s_float); - pd_bind(&x->x_obj.ob_pd, midiclkin_sym); + pd_bind(&x->x_obj.ob_pd, pd_this->pd_midiclkin_sym); return (x); } @@ -550,17 +525,16 @@ static void midiclkin_list(t_midiclkin *x, t_symbol *s, int argc, t_atom *argv) static void midiclkin_free(t_midiclkin *x) { - pd_unbind(&x->x_obj.ob_pd, midiclkin_sym); + pd_unbind(&x->x_obj.ob_pd, pd_this->pd_midiclkin_sym); } static void midiclkin_setup(void) { - midiclkin_class = class_new(gensym("midiclkin"), - (t_newmethod)midiclkin_new, (t_method)midiclkin_free, + midiclkin_class = class_new(gensym("midiclkin"), + (t_newmethod)midiclkin_new, (t_method)midiclkin_free, sizeof(t_midiclkin), CLASS_NOINLET, A_DEFFLOAT, 0); class_addlist(midiclkin_class, midiclkin_list); class_sethelpsymbol(midiclkin_class, gensym("midi")); - midiclkin_sym = gensym("#midiclkin"); } void inmidi_clk(double timing) @@ -568,14 +542,14 @@ void inmidi_clk(double timing) static t_float prev = 0; static t_float count = 0; - t_float diff; + t_float cur,diff; - if (midiclkin_sym->s_thing) + if (pd_this->pd_midiclkin_sym->s_thing) { t_atom at[2]; diff =timing - prev; count++; - + if (count == 3) { /* 24 count per quoter note */ SETFLOAT(at, 1 ); @@ -584,15 +558,13 @@ void inmidi_clk(double timing) else SETFLOAT(at, 0); SETFLOAT(at+1, diff); - pd_list(midiclkin_sym->s_thing, &s_list, 2, at); + pd_list(pd_this->pd_midiclkin_sym->s_thing, &s_list, 2, at); prev = timing; } } /*----------midirealtimein (midi FA,FB,FC,FF message )-----------------*/ -static t_symbol *midirealtimein_sym; - static t_class *midirealtimein_class; typedef struct _midirealtimein @@ -607,10 +579,7 @@ static void *midirealtimein_new( void) t_midirealtimein *x = (t_midirealtimein *)pd_new(midirealtimein_class); x->x_outlet1 = outlet_new(&x->x_obj, &s_float); x->x_outlet2 = outlet_new(&x->x_obj, &s_float); - pd_bind(&x->x_obj.ob_pd, midirealtimein_sym); -#ifndef MSW - pd_error(x, "midirealtimein: works under MSW only"); -#endif + pd_bind(&x->x_obj.ob_pd, pd_this->pd_midirealtimein_sym); return (x); } @@ -626,27 +595,26 @@ static void midirealtimein_list(t_midirealtimein *x, t_symbol *s, static void midirealtimein_free(t_midirealtimein *x) { - pd_unbind(&x->x_obj.ob_pd, midirealtimein_sym); + pd_unbind(&x->x_obj.ob_pd, pd_this->pd_midirealtimein_sym); } static void midirealtimein_setup(void) { - midirealtimein_class = class_new(gensym("midirealtimein"), - (t_newmethod)midirealtimein_new, (t_method)midirealtimein_free, + midirealtimein_class = class_new(gensym("midirealtimein"), + (t_newmethod)midirealtimein_new, (t_method)midirealtimein_free, sizeof(t_midirealtimein), CLASS_NOINLET, A_DEFFLOAT, 0); 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->s_thing) + if (pd_this->pd_midirealtimein_sym->s_thing) { t_atom at[2]; SETFLOAT(at, portno); SETFLOAT(at+1, SysMsg); - pd_list(midirealtimein_sym->s_thing, &s_list, 2, at); + pd_list(pd_this->pd_midirealtimein_sym->s_thing, &s_list, 2, at); } } @@ -668,9 +636,6 @@ static void *midiout_new(t_floatarg portno) if (portno <= 0) portno = 1; x->x_portno = portno; floatinlet_new(&x->x_obj, &x->x_portno); -#ifdef __irix__ - post("midiout: unimplemented in IRIX"); -#endif return (x); } @@ -723,6 +688,7 @@ static void noteout_setup(void) noteout_class = class_new(gensym("noteout"), (t_newmethod)noteout_new, 0, sizeof(t_noteout), 0, A_DEFFLOAT, 0); class_addfloat(noteout_class, noteout_float); + class_sethelpsymbol(noteout_class, gensym("midi")); } @@ -762,6 +728,7 @@ static void ctlout_setup(void) ctlout_class = class_new(gensym("ctlout"), (t_newmethod)ctlout_new, 0, sizeof(t_ctlout), 0, A_DEFFLOAT, A_DEFFLOAT, 0); class_addfloat(ctlout_class, ctlout_float); + class_sethelpsymbol(ctlout_class, gensym("midi")); } @@ -801,6 +768,7 @@ static void pgmout_setup(void) pgmout_class = class_new(gensym("pgmout"), (t_newmethod)pgmout_new, 0, sizeof(t_pgmout), 0, A_DEFFLOAT, 0); class_addfloat(pgmout_class, pgmout_float); + class_sethelpsymbol(pgmout_class, gensym("midi")); } @@ -837,6 +805,7 @@ static void bendout_setup(void) bendout_class = class_new(gensym("bendout"), (t_newmethod)bendout_new, 0, sizeof(t_bendout), 0, A_DEFFLOAT, 0); class_addfloat(bendout_class, bendout_float); + class_sethelpsymbol(bendout_class, gensym("midi")); } /* -------------------------- touch -------------------------- */ @@ -906,7 +875,7 @@ static void polytouchout_float(t_polytouchout *x, t_float n) static void polytouchout_setup(void) { - polytouchout_class = class_new(gensym("polytouchout"), + polytouchout_class = class_new(gensym("polytouchout"), (t_newmethod)polytouchout_new, 0, sizeof(t_polytouchout), 0, A_DEFFLOAT, 0); class_addfloat(polytouchout_class, polytouchout_float); @@ -955,7 +924,7 @@ static void makenote_tick(t_hang *hang) outlet_float(x->x_velout, 0); outlet_float(x->x_pitchout, hang->h_pitch); if (x->x_hang == hang) x->x_hang = hang->h_next; - else for (h2 = x->x_hang; h3 = h2->h_next; h2 = h3) + else for (h2 = x->x_hang; (h3 = h2->h_next); h2 = h3) { if (h3 == hang) { @@ -985,7 +954,7 @@ static void makenote_float(t_makenote *x, t_float f) static void makenote_stop(t_makenote *x) { t_hang *hang; - while (hang = x->x_hang) + while ((hang = x->x_hang)) { outlet_float(x->x_velout, 0); outlet_float(x->x_pitchout, hang->h_pitch); @@ -998,7 +967,7 @@ static void makenote_stop(t_makenote *x) static void makenote_clear(t_makenote *x) { t_hang *hang; - while (hang = x->x_hang) + while ((hang = x->x_hang)) { x->x_hang = hang->h_next; clock_free(hang->h_clock); @@ -1008,7 +977,7 @@ static void makenote_clear(t_makenote *x) static void makenote_setup(void) { - makenote_class = class_new(gensym("makenote"), + makenote_class = class_new(gensym("makenote"), (t_newmethod)makenote_new, (t_method)makenote_clear, sizeof(t_makenote), 0, A_DEFFLOAT, A_DEFFLOAT, 0); class_addfloat(makenote_class, makenote_float); @@ -1038,9 +1007,10 @@ static void *stripnote_new(void ) x->x_velout = outlet_new(&x->x_obj, &s_float); return (x); } - + static void stripnote_float(t_stripnote *x, t_float f) { + t_hang *hang; if (!x->x_velo) return; outlet_float(x->x_velout, x->x_velo); outlet_float(x->x_pitchout, f); @@ -1179,7 +1149,7 @@ static void poly_free(t_poly *x) static void poly_setup(void) { - poly_class = class_new(gensym("poly"), + poly_class = class_new(gensym("poly"), (t_newmethod)poly_new, (t_method)poly_free, sizeof(t_poly), 0, A_DEFFLOAT, A_DEFFLOAT, 0); class_addfloat(poly_class, poly_float); @@ -1225,7 +1195,7 @@ static void bag_float(t_bag *x, t_float f) if (!x->x_first) x->x_first = bagelem; else /* LATER replace with a faster algorithm */ { - for (e2 = x->x_first; e3 = e2->e_next; e2 = e3) + for (e2 = x->x_first; (e3 = e2->e_next); e2 = e3) ; e2->e_next = bagelem; } @@ -1240,7 +1210,7 @@ static void bag_float(t_bag *x, t_float f) freebytes(bagelem, sizeof(*bagelem)); return; } - for (e2 = x->x_first; e3 = e2->e_next; e2 = e3) + for (e2 = x->x_first; (e3 = e2->e_next); e2 = e3) if (e3->e_value == f) { e2->e_next = e3->e_next; @@ -1253,7 +1223,7 @@ static void bag_float(t_bag *x, t_float f) static void bag_flush(t_bag *x) { t_bagelem *bagelem; - while (bagelem = x->x_first) + while ((bagelem = x->x_first)) { outlet_float(x->x_obj.ob_outlet, bagelem->e_value); x->x_first = bagelem->e_next; @@ -1264,7 +1234,7 @@ static void bag_flush(t_bag *x) static void bag_clear(t_bag *x) { t_bagelem *bagelem; - while (bagelem = x->x_first) + while ((bagelem = x->x_first)) { x->x_first = bagelem->e_next; freebytes(bagelem, sizeof(*bagelem)); @@ -1273,7 +1243,7 @@ static void bag_clear(t_bag *x) static void bag_setup(void) { - bag_class = class_new(gensym("bag"), + bag_class = class_new(gensym("bag"), (t_newmethod)bag_new, (t_method)bag_clear, sizeof(t_bag), 0, 0); class_addfloat(bag_class, bag_float); @@ -1281,6 +1251,10 @@ static void bag_setup(void) class_addmethod(bag_class, (t_method)bag_clear, gensym("clear"), 0); } +void sys_setmidiprefix(const char *prefix) +{ +} + void x_midi_setup(void) { midiin_setup(); diff --git a/pd/src/x_misc.c b/pd/src/x_misc.c index f313041026ea6d0ec14b1553aa271febf20d4730..9f019cbf0d8905ede5aab1b7761eac19721fc390 100644 --- a/pd/src/x_misc.c +++ b/pd/src/x_misc.c @@ -390,6 +390,406 @@ static void realtime_setup(void) 0); } +/* ---------- oscparse - parse simple OSC messages ----------------- */ + +static t_class *oscparse_class; + +typedef struct _oscparse +{ + t_object x_obj; +} t_oscparse; + +#define ROUNDUPTO4(x) (((x) + 3) & (~3)) + +#define READINT(x) ((((int)(((x) )->a_w.w_float)) & 0xff) << 24) | \ + ((((int)(((x)+1)->a_w.w_float)) & 0xff) << 16) | \ + ((((int)(((x)+2)->a_w.w_float)) & 0xff) << 8) | \ + ((((int)(((x)+3)->a_w.w_float)) & 0xff) << 0) + +static t_symbol *grabstring(int argc, t_atom *argv, int *ip, int slash) +{ + char buf[MAXPDSTRING]; + int first, nchar; + if (slash) + while (*ip < argc && argv[*ip].a_w.w_float == '/') + (*ip)++; + for (nchar = 0; nchar < MAXPDSTRING-1 && *ip < argc; nchar++, (*ip)++) + { + char c = argv[*ip].a_w.w_float; + if (c == 0 || (slash && c == '/')) + break; + buf[nchar] = c; + } + buf[nchar] = 0; + if (!slash) + *ip = ROUNDUPTO4(*ip+1); + if (*ip > argc) + *ip = argc; + return (gensym(buf)); +} + +static void oscparse_list(t_oscparse *x, t_symbol *s, int argc, t_atom *argv) +{ + int i, j, j2, k, outc = 1, blob = 0, typeonset, dataonset, nfield; + t_atom *outv; + if (!argc) + return; + for (i = 0; i < argc; i++) + if (argv[i].a_type != A_FLOAT) + { + pd_error(x, "oscparse: takes numbers only"); + return; + } + if (argv[0].a_w.w_float == '#') /* it's a bundle */ + { + if (argv[1].a_w.w_float != 'b' || argc < 16) + { + pd_error(x, "oscparse: malformed bundle"); + return; + } + /* we ignore the timetag since there's no correct way to + convert it to Pd logical time that I can think of. LATER + consider at least outputting timetag differentially converted + into Pd time units. */ + for (i = 16; i < argc-4; ) + { + int msize = READINT(argv+i); + if (msize <= 0 || msize & 3) + { + pd_error(x, "oscparse: bad bundle element size"); + return; + } + oscparse_list(x, 0, msize, argv+i+4); + i += msize+4; + } + return; + } + else if (argv[0].a_w.w_float != '/') + { + pd_error(x, "oscparse: not an OSC message (no leading slash)"); + return; + } + for (i = 1; i < argc && argv[i].a_w.w_float != 0; i++) + if (argv[i].a_w.w_float == '/') + outc++; + i = ROUNDUPTO4(i+1); + if (argv[i].a_w.w_float != ',' || (i+1) >= argc) + { + pd_error(x, "oscparse: malformed type string (char %d, index %d)", + (int)(argv[i].a_w.w_float), i); + return; + } + typeonset = ++i; + for (; i < argc && argv[i].a_w.w_float != 0; i++) + if (argv[i].a_w.w_float == 'b') + blob = 1; + nfield = i - typeonset; + if (blob) + outc += argc - typeonset; + else outc += nfield; + outv = (t_atom *)alloca(outc * sizeof(t_atom)); + dataonset = ROUNDUPTO4(i + 1); + /* post("outc %d, typeonset %d, dataonset %d, nfield %d", outc, typeonset, + dataonset, nfield); */ + for (i = j = 0; i < typeonset-1 && argv[i].a_w.w_float != 0 && + j < outc; j++) + SETSYMBOL(outv+j, grabstring(argc, argv, &i, 1)); + for (i = typeonset, k = dataonset; i < typeonset + nfield; i++) + { + union + { + float z_f; + uint32_t z_i; + } z; + float f; + int blobsize; + switch ((int)(argv[i].a_w.w_float)) + { + case 'f': + if (k > argc - 4) + goto tooshort; + z.z_i = READINT(argv+k); + f = z.z_f; + if (PD_BADFLOAT(f)) + f = 0; + if (j >= outc) + { + bug("oscparse 1: %d >=%d", j, outc); + return; + } + SETFLOAT(outv+j, f); + j++; k += 4; + break; + case 'i': + if (k > argc - 4) + goto tooshort; + if (j >= outc) + { + bug("oscparse 2"); + return; + } + SETFLOAT(outv+j, READINT(argv+k)); + j++; k += 4; + break; + case 's': + if (j >= outc) + { + bug("oscparse 3"); + return; + } + SETSYMBOL(outv+j, grabstring(argc, argv, &k, 0)); + j++; + break; + case 'b': + if (k > argc - 4) + goto tooshort; + blobsize = READINT(argv+k); + k += 4; + if (blobsize < 0 || blobsize > argc - k) + goto tooshort; + if (j + blobsize + 1 > outc) + { + bug("oscparse 4"); + return; + } + if (k + blobsize > argc) + goto tooshort; + SETFLOAT(outv+j, blobsize); + j++; + for (j2 = 0; j2 < blobsize; j++, j2++, k++) + SETFLOAT(outv+j, argv[k].a_w.w_float); + k = ROUNDUPTO4(k); + break; + default: + pd_error(x, "oscparse: unknown tag '%c' (%d)", + (int)(argv[i].a_w.w_float), (int)(argv[i].a_w.w_float)); + } + } + outlet_list(x->x_obj.ob_outlet, 0, j, outv); + return; +tooshort: + pd_error(x, "oscparse: OSC message ended prematurely"); +} + +static t_oscparse *oscparse_new(t_symbol *s, int argc, t_atom *argv) +{ + t_oscparse *x = (t_oscparse *)pd_new(oscparse_class); + outlet_new(&x->x_obj, gensym("list")); + return (x); +} + +void oscparse_setup(void) +{ + oscparse_class = class_new(gensym("oscparse"), (t_newmethod)oscparse_new, + 0, sizeof(t_oscparse), 0, A_GIMME, 0); + class_addlist(oscparse_class, oscparse_list); +} + +/* --------- oscformat - format simple OSC messages -------------- */ +static t_class *oscformat_class; + +typedef struct _oscformat +{ + t_object x_obj; + char *x_pathbuf; + int x_pathsize; + t_symbol *x_format; +} t_oscformat; + +static void oscformat_set(t_oscformat *x, t_symbol *s, int argc, t_atom *argv) +{ + char buf[MAXPDSTRING]; + int i, newsize; + *x->x_pathbuf = 0; + buf[0] = '/'; + for (i = 0; i < argc; i++) + { + char *where = (argv[i].a_type == A_SYMBOL && + *argv[i].a_w.w_symbol->s_name == '/' ? buf : buf+1); + atom_string(&argv[i], where, MAXPDSTRING-1); + if ((newsize = strlen(buf) + strlen(x->x_pathbuf) + 1) > x->x_pathsize) + { + x->x_pathbuf = resizebytes(x->x_pathbuf, x->x_pathsize, newsize); + x->x_pathsize = newsize; + } + strcat(x->x_pathbuf, buf); + } +} + +static void oscformat_format(t_oscformat *x, t_symbol *s) +{ + char *sp; + for (sp = s->s_name; *sp; sp++) + { + if (*sp != 'f' && *sp != 'i' && *sp != 's' && *sp != 'b') + { + pd_error(x, + "oscformat '%s' may only contain 'f', 'i'. 's', and/or 'b'", + sp); + return; + } + } + x->x_format = s; +} + +#define WRITEINT(msg, i) SETFLOAT((msg), (((i) >> 24) & 0xff)); \ + SETFLOAT((msg)+1, (((i) >> 16) & 0xff)); \ + SETFLOAT((msg)+2, (((i) >> 8) & 0xff)); \ + SETFLOAT((msg)+3, (((i) ) & 0xff)) + +static void putstring(t_atom *msg, int *ip, const char *s) +{ + const char *sp = s; + do + { + SETFLOAT(&msg[*ip], *sp & 0xff); + (*ip)++; + } + while (*sp++); + while (*ip & 3) + { + SETFLOAT(&msg[*ip], 0); + (*ip)++; + } +} + +static void oscformat_list(t_oscformat *x, t_symbol *s, int argc, t_atom *argv) +{ + int typeindex = 0, j, msgindex, msgsize, datastart, ndata; + t_atom *msg; + char *sp, *formatp = x->x_format->s_name, typecode; + /* pass 1: go through args to find overall message size */ + for (j = ndata = 0, sp = formatp, msgindex = 0; j < argc;) + { + if (*sp) + typecode = *sp++; + else if (argv[j].a_type == A_SYMBOL) + typecode = 's'; + else typecode = 'f'; + if (typecode == 's') + msgindex += ROUNDUPTO4(strlen(argv[j].a_w.w_symbol->s_name) + 1); + else if (typecode == 'b') + { + int blobsize = 0x7fffffff, blobindex; + /* check if we have a nonnegative size field */ + if (argv[j].a_type == A_FLOAT && + (int)(argv[j].a_w.w_float) >= 0) + blobsize = (int)(argv[j].a_w.w_float); + if (blobsize > argc - j - 1) + blobsize = argc - j - 1; /* if no or bad size, eat it all */ + msgindex += 4 + ROUNDUPTO4(blobsize); + j += blobsize; + } + else msgindex += 4; + j++; + ndata++; + } + datastart = ROUNDUPTO4(strlen(x->x_pathbuf)+1) + ROUNDUPTO4(ndata + 2); + msgsize = datastart + msgindex; + msg = (t_atom *)alloca(msgsize * sizeof(t_atom)); + putstring(msg, &typeindex, x->x_pathbuf); + SETFLOAT(&msg[typeindex], ','); + typeindex++; + /* pass 2: fill in types and data portion of packet */ + for (j = 0, sp = formatp, msgindex = datastart; j < argc;) + { + if (*sp) + typecode = *sp++; + else if (argv[j].a_type == A_SYMBOL) + typecode = 's'; + else typecode = 'f'; + SETFLOAT(&msg[typeindex], typecode & 0xff); + typeindex++; + if (typecode == 'f') + { + union + { + float z_f; + uint32_t z_i; + } z; + z.z_f = atom_getfloat(&argv[j]); + WRITEINT(msg+msgindex, z.z_i); + msgindex += 4; + } + else if (typecode == 'i') + { + int dat = atom_getfloat(&argv[j]); + WRITEINT(msg+msgindex, dat); + msgindex += 4; + } + else if (typecode == 's') + putstring(msg, &msgindex, argv[j].a_w.w_symbol->s_name); + else if (typecode == 'b') + { + int blobsize = 0x7fffffff, blobindex; + if (argv[j].a_type == A_FLOAT && + (int)(argv[j].a_w.w_float) >= 0) + blobsize = (int)(argv[j].a_w.w_float); + if (blobsize > argc - j - 1) + blobsize = argc - j - 1; + WRITEINT(msg+msgindex, blobsize); + msgindex += 4; + for (blobindex = 0; blobindex < blobsize; blobindex++) + SETFLOAT(msg+msgindex+blobindex, + (argv[j+1+blobindex].a_type == A_FLOAT ? + argv[j+1+blobindex].a_w.w_float : + (argv[j+1+blobindex].a_type == A_SYMBOL ? + argv[j+1+blobindex].a_w.w_symbol->s_name[0] & 0xff : + 0))); + j += blobsize; + while (blobsize & 3) + SETFLOAT(msg+msgindex+blobsize, 0), blobsize++; + msgindex += blobsize; + } + j++; + } + SETFLOAT(&msg[typeindex], 0); + typeindex++; + while (typeindex & 3) + SETFLOAT(&msg[typeindex], 0), typeindex++; + if (typeindex != datastart || msgindex != msgsize) + bug("oscformat: typeindex %d, datastart %d, msgindex %d, msgsize %d", + typeindex, datastart, msgindex, msgsize); + /* else post("datastart %d, msgsize %d", datastart, msgsize); */ + outlet_list(x->x_obj.ob_outlet, 0, msgsize, msg); +} + +static void oscformat_free(t_oscformat *x) +{ + freebytes(x->x_pathbuf, x->x_pathsize); +} + +static void *oscformat_new(t_symbol *s, int argc, t_atom *argv) +{ + t_oscformat *x = (t_oscformat *)pd_new(oscformat_class); + outlet_new(&x->x_obj, gensym("list")); + x->x_pathbuf = getbytes(1); + x->x_pathsize = 1; + *x->x_pathbuf = 0; + x->x_format = &s_; + if (argc > 1 && argv[0].a_type == A_SYMBOL && + argv[1].a_type == A_SYMBOL && + !strcmp(argv[0].a_w.w_symbol->s_name, "-f")) + { + oscformat_format(x, argv[1].a_w.w_symbol); + argc -= 2; + argv += 2; + } + oscformat_set(x, 0, argc, argv); + return (x); +} + +void oscformat_setup(void) +{ + oscformat_class = class_new(gensym("oscformat"), (t_newmethod)oscformat_new, + (t_method)oscformat_free, sizeof(t_oscformat), 0, A_GIMME, 0); + class_addmethod(oscformat_class, (t_method)oscformat_set, + gensym("set"), A_GIMME, 0); + class_addmethod(oscformat_class, (t_method)oscformat_format, + gensym("format"), A_DEFSYM, 0); + class_addlist(oscformat_class, oscformat_list); +} + void x_misc_setup(void) { random_setup(); @@ -400,4 +800,6 @@ void x_misc_setup(void) serial_setup(); cputime_setup(); realtime_setup(); + oscparse_setup(); + oscformat_setup(); } diff --git a/pd/src/x_net.c b/pd/src/x_net.c index bb3c4970274dd7a3c3d6b6fa30e3c4be005ba20d..ed7aa2ec0bc57d53e14ecf582fbce1415ae22439 100644 --- a/pd/src/x_net.c +++ b/pd/src/x_net.c @@ -9,7 +9,7 @@ #include <sys/types.h> #include <string.h> -#ifdef MSW +#ifdef _WIN32 #include <winsock.h> #else #include <sys/socket.h> @@ -20,33 +20,152 @@ #define SOCKET_ERROR -1 #endif +#ifdef _WIN32 +# include <malloc.h> /* MSVC or mingw on windows */ +#elif defined(__linux__) || defined(__APPLE__) +# include <alloca.h> /* linux, mac, mingw, cygwin */ +#else +# include <stdlib.h> /* BSDs for example */ +#endif + static t_class *netsend_class; typedef struct _netsend { t_object x_obj; - int x_fd; + t_outlet *x_msgout; + t_outlet *x_connectout; + int x_sockfd; int x_protocol; + int x_bin; } t_netsend; -static void *netsend_new(t_floatarg udpflag) +static t_class *netreceive_class; + +typedef struct _netreceive +{ + t_netsend x_ns; + int x_nconnections; + int x_sockfd; + int *x_connections; + int x_old; +} t_netreceive; + +static void netreceive_notify(t_netreceive *x, int fd); + +static void *netsend_new(t_symbol *s, int argc, t_atom *argv) { t_netsend *x = (t_netsend *)pd_new(netsend_class); outlet_new(&x->x_obj, &s_float); - x->x_fd = -1; - x->x_protocol = (udpflag != 0 ? SOCK_DGRAM : SOCK_STREAM); + x->x_protocol = SOCK_STREAM; + x->x_bin = 0; + if (argc && argv->a_type == A_FLOAT) + { + x->x_protocol = (argv->a_w.w_float != 0 ? SOCK_DGRAM : SOCK_STREAM); + argc = 0; + } + else while (argc && argv->a_type == A_SYMBOL && + *argv->a_w.w_symbol->s_name == '-') + { + if (!strcmp(argv->a_w.w_symbol->s_name, "-b")) + x->x_bin = 1; + else if (!strcmp(argv->a_w.w_symbol->s_name, "-u")) + x->x_protocol = SOCK_DGRAM; + else + { + pd_error(x, "netsend: unknown flag ..."); + postatom(argc, argv); endpost(); + } + argc--; argv++; + } + if (argc) + { + pd_error(x, "netsend: extra arguments ignored:"); + postatom(argc, argv); endpost(); + } + x->x_sockfd = -1; + x->x_msgout = outlet_new(&x->x_obj, &s_anything); return (x); } +static void netsend_readbin(t_netsend *x, int fd) +{ + unsigned char inbuf[MAXPDSTRING]; + int ret = recv(fd, inbuf, MAXPDSTRING, 0), i; + if (!x->x_msgout) + { + bug("netsend_readbin"); + return; + } + if (ret <= 0) + { + if (ret < 0) + sys_sockerror("recv"); + sys_rmpollfn(fd); + sys_closesocket(fd); + if (x->x_obj.ob_pd == netreceive_class) + netreceive_notify((t_netreceive *)x, fd); + } + else if (x->x_protocol == SOCK_DGRAM) + { + t_atom *ap = (t_atom *)alloca(ret * sizeof(t_atom)); + for (i = 0; i < ret; i++) + SETFLOAT(ap+i, inbuf[i]); + outlet_list(x->x_msgout, 0, ret, ap); + } + else + { + for (i = 0; i < ret; i++) + outlet_float(x->x_msgout, inbuf[i]); + } +} + +static void netsend_doit(void *z, t_binbuf *b) +{ + t_atom messbuf[1024]; + t_netsend *x = (t_netsend *)z; + int msg, natom = binbuf_getnatom(b); + t_atom *at = binbuf_getvec(b); + for (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) + { + int i; + for (i = msg; i < emsg; i++) + if (at[i].a_type == A_DOLLAR || at[i].a_type == A_DOLLSYM) + { + pd_error(x, "netreceive: got dollar sign in message"); + goto nodice; + } + if (at[msg].a_type == A_FLOAT) + { + if (emsg > msg + 1) + outlet_list(x->x_msgout, 0, emsg-msg, at + msg); + else outlet_float(x->x_msgout, at[msg].a_w.w_float); + } + else if (at[msg].a_type == A_SYMBOL) + outlet_anything(x->x_msgout, at[msg].a_w.w_symbol, + emsg-msg-1, at + msg + 1); + } + nodice: + msg = emsg + 1; + } +} + + static void netsend_connect(t_netsend *x, t_symbol *hostname, t_floatarg fportno) { - struct sockaddr_in server; + struct sockaddr_in server = {0}; struct hostent *hp; int sockfd; int portno = fportno; int intarg; - if (x->x_fd >= 0) + if (x->x_sockfd >= 0) { error("netsend_connect: already connected"); return; @@ -68,6 +187,7 @@ static void netsend_connect(t_netsend *x, t_symbol *hostname, if (hp == 0) { post("bad host?\n"); + sys_closesocket(sockfd); return; } #if 0 @@ -76,6 +196,10 @@ static void netsend_connect(t_netsend *x, t_symbol *hostname, &intarg, sizeof(intarg)) < 0) post("setsockopt (SO_RCVBUF) failed\n"); #endif + intarg = 1; + if(setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, + (const void *)&intarg, sizeof(intarg)) < 0) + post("setting SO_BROADCAST"); /* for stream (TCP) sockets, specify "nodelay" */ if (x->x_protocol == SOCK_STREAM) { @@ -98,67 +222,105 @@ static void netsend_connect(t_netsend *x, t_symbol *hostname, sys_closesocket(sockfd); return; } - x->x_fd = sockfd; + x->x_sockfd = sockfd; + if (x->x_msgout) /* add polling function for return messages */ + { + if (x->x_bin) + sys_addpollfn(sockfd, (t_fdpollfn)netsend_readbin, x); + else + { + t_socketreceiver *y = + socketreceiver_new((void *)x, 0, netsend_doit, + x->x_protocol == SOCK_DGRAM); + sys_addpollfn(sockfd, (t_fdpollfn)socketreceiver_read, y); + } + } outlet_float(x->x_obj.ob_outlet, 1); } static void netsend_disconnect(t_netsend *x) { - if (x->x_fd >= 0) + if (x->x_sockfd >= 0) { - sys_closesocket(x->x_fd); - x->x_fd = -1; + sys_rmpollfn(x->x_sockfd); + sys_closesocket(x->x_sockfd); + x->x_sockfd = -1; outlet_float(x->x_obj.ob_outlet, 0); } } -static void netsend_send(t_netsend *x, t_symbol *s, int argc, t_atom *argv) +static int netsend_dosend(t_netsend *x, int sockfd, + t_symbol *s, int argc, t_atom *argv) { - if (x->x_fd >= 0) + char *buf, *bp; + int length, sent, fail = 0; + t_binbuf *b = 0; + if (x->x_bin) + { + int i; + buf = alloca(argc); + for (i = 0; i < argc; i++) + ((unsigned char *)buf)[i] = atom_getfloatarg(i, argc, argv); + length = argc; + } + else { - t_binbuf *b = binbuf_new(); - char *buf, *bp; - int length, sent; t_atom at; + b = binbuf_new(); binbuf_add(b, argc, argv); SETSEMI(&at); binbuf_add(b, 1, &at); binbuf_gettext(b, &buf, &length); - for (bp = buf, sent = 0; sent < length;) + } + for (bp = buf, sent = 0; sent < length;) + { + static double lastwarntime; + static double pleasewarn; + double timebefore = sys_getrealtime(); + int res = send(sockfd, bp, length-sent, 0); + double timeafter = sys_getrealtime(); + int late = (timeafter - timebefore > 0.005); + if (late || pleasewarn) { - static double lastwarntime; - static double pleasewarn; - double timebefore = sys_getrealtime(); - int res = send(x->x_fd, bp, length-sent, 0); - double timeafter = sys_getrealtime(); - int late = (timeafter - timebefore > 0.005); - if (late || pleasewarn) + if (timeafter > lastwarntime + 2) { - 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; + post("netsend/netreceive blocked %d msec", + (int)(1000 * ((timeafter - timebefore) + + pleasewarn))); + pleasewarn = 0; + lastwarntime = timeafter; } + else if (late) pleasewarn += timeafter - timebefore; + } + if (res <= 0) + { + sys_sockerror("netsend"); + fail = 1; + break; } + else + { + sent += res; + bp += res; + } + } + done: + if (!x->x_bin) + { t_freebytes(buf, length); binbuf_free(b); } - else error("netsend: not connected"); + return (fail); +} + + +static void netsend_send(t_netsend *x, t_symbol *s, int argc, t_atom *argv) +{ + if (x->x_sockfd >= 0) + { + if (netsend_dosend(x, x->x_sockfd, s, argc, argv)) + netsend_disconnect(x); + } } static void netsend_free(t_netsend *x) @@ -170,7 +332,7 @@ static void netsend_setup(void) { netsend_class = class_new(gensym("netsend"), (t_newmethod)netsend_new, (t_method)netsend_free, - sizeof(t_netsend), 0, A_DEFFLOAT, 0); + sizeof(t_netsend), 0, A_GIMME, 0); class_addmethod(netsend_class, (t_method)netsend_connect, gensym("connect"), A_SYMBOL, A_FLOAT, 0); class_addmethod(netsend_class, (t_method)netsend_disconnect, @@ -180,184 +342,229 @@ static void netsend_setup(void) } /* ----------------------------- netreceive ------------------------- */ - -static t_class *netreceive_class; - -typedef struct _netreceive -{ - t_object x_obj; - t_outlet *x_msgout; - t_outlet *x_connectout; - int x_acceptsocket; - int x_connectsocket; - int x_nconnections; - int x_udp; -} t_netreceive; - -static void netreceive_notify(t_netreceive *x) -{ - outlet_float(x->x_connectout, --x->x_nconnections); -} - -static void netreceive_doit(void *z, t_binbuf *b) +static void netreceive_notify(t_netreceive *x, int fd) { - t_netreceive *x = (t_netreceive *)z; - int msg, natom = binbuf_getnatom(b); - t_atom *at = binbuf_getvec(b); - for (msg = 0; msg < natom;) + int i; + for (i = 0; i < x->x_nconnections; i++) { - int emsg; - for (emsg = msg; emsg < natom && at[emsg].a_type != A_COMMA - && at[emsg].a_type != A_SEMI; emsg++) - ; - if (emsg > msg) + if (x->x_connections[i] == fd) { - int i; - for (i = msg; i < emsg; i++) - if (at[i].a_type == A_DOLLAR || at[i].a_type == A_DOLLSYM) - { - pd_error(x, "netreceive: got dollar sign in message"); - goto nodice; - } - if (at[msg].a_type == A_FLOAT) - { - if (emsg > msg + 1) - outlet_list(x->x_msgout, 0, emsg-msg, at + msg); - else outlet_float(x->x_msgout, at[msg].a_w.w_float); - } - else if (at[msg].a_type == A_SYMBOL) - outlet_anything(x->x_msgout, at[msg].a_w.w_symbol, - emsg-msg-1, at + msg + 1); + memmove(x->x_connections+i, x->x_connections+(i+1), + sizeof(int) * (x->x_nconnections - (i+1))); + x->x_connections = (int *)t_resizebytes(x->x_connections, + x->x_nconnections * sizeof(int), + (x->x_nconnections-1) * sizeof(int)); + x->x_nconnections--; } - nodice: - msg = emsg + 1; } + outlet_float(x->x_ns.x_connectout, x->x_nconnections); } static void netreceive_connectpoll(t_netreceive *x) { - int fd = accept(x->x_connectsocket, 0, 0); + int fd = accept(x->x_ns.x_sockfd, 0, 0); if (fd < 0) post("netreceive: accept failed"); else { - t_socketreceiver *y = socketreceiver_new((void *)x, + int nconnections = x->x_nconnections+1; + + x->x_connections = (int *)t_resizebytes(x->x_connections, + x->x_nconnections * sizeof(int), nconnections * sizeof(int)); + x->x_connections[x->x_nconnections] = fd; + if (x->x_ns.x_bin) + sys_addpollfn(fd, (t_fdpollfn)netsend_readbin, x); + else + { + t_socketreceiver *y = socketreceiver_new((void *)x, (t_socketnotifier)netreceive_notify, - (x->x_msgout ? netreceive_doit : 0), 0); - sys_addpollfn(fd, (t_fdpollfn)socketreceiver_read, y); - x->x_acceptsocket = fd; - outlet_float(x->x_connectout, ++x->x_nconnections); + (x->x_ns.x_msgout ? netsend_doit : 0), 0); + sys_addpollfn(fd, (t_fdpollfn)socketreceiver_read, y); + } + outlet_float(x->x_ns.x_connectout, (x->x_nconnections = nconnections)); } } -static void *netreceive_new(t_symbol *compatflag, - t_floatarg fportno, t_floatarg udpflag) +static void netreceive_closeall(t_netreceive *x) { - t_netreceive *x; - struct sockaddr_in server; - int sockfd, portno = fportno, udp = (udpflag != 0); - int old = !strcmp(compatflag->s_name , "old"); - int intarg; - /* create a socket */ - sockfd = socket(AF_INET, (udp ? SOCK_DGRAM : SOCK_STREAM), 0); -#if 0 - fprintf(stderr, "receive socket %d\n", sockfd); -#endif - if (sockfd < 0) + int i; + for (i = 0; i < x->x_nconnections; i++) + { + sys_rmpollfn(x->x_connections[i]); + sys_closesocket(x->x_connections[i]); + } + x->x_connections = (int *)t_resizebytes(x->x_connections, + x->x_nconnections * sizeof(int), 0); + x->x_nconnections = 0; + if (x->x_ns.x_sockfd >= 0) + { + sys_rmpollfn(x->x_ns.x_sockfd); + sys_closesocket(x->x_ns.x_sockfd); + } + x->x_ns.x_sockfd = -1; +} + +static void netreceive_listen(t_netreceive *x, t_floatarg fportno) +{ + int portno = fportno, intarg; + struct sockaddr_in server = {0}; + netreceive_closeall(x); + if (portno <= 0) + return; + x->x_ns.x_sockfd = socket(AF_INET, x->x_ns.x_protocol, 0); + if (x->x_ns.x_sockfd < 0) { sys_sockerror("socket"); - return (0); + return; } - server.sin_family = AF_INET; - server.sin_addr.s_addr = INADDR_ANY; +#if 0 + fprintf(stderr, "receive socket %d\n", x->x_ sockfd); +#endif #if 1 /* ask OS to allow another Pd to repoen this port after we close it. */ intarg = 1; - if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, + if (setsockopt(x->x_ns.x_sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&intarg, sizeof(intarg)) < 0) - post("setsockopt (SO_REUSEADDR) failed\n"); + post("netreceive: setsockopt (SO_REUSEADDR) failed\n"); #endif #if 0 intarg = 0; - if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, + if (setsockopt(x->x_ns.x_sockfd, SOL_SOCKET, SO_RCVBUF, &intarg, sizeof(intarg)) < 0) post("setsockopt (SO_RCVBUF) failed\n"); #endif + intarg = 1; + if (setsockopt(x->x_ns.x_sockfd, SOL_SOCKET, SO_BROADCAST, + (const void *)&intarg, sizeof(intarg)) < 0) + post("netreceive: failed to sett SO_BROADCAST"); /* Stream (TCP) sockets are set NODELAY */ - if (!udp) + if (x->x_ns.x_protocol == SOCK_STREAM) { intarg = 1; - if (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, + if (setsockopt(x->x_ns.x_sockfd, IPPROTO_TCP, TCP_NODELAY, (char *)&intarg, sizeof(intarg)) < 0) post("setsockopt (TCP_NODELAY) failed\n"); } - /* assign server port number */ + /* assign server port number etc */ + server.sin_family = AF_INET; + server.sin_addr.s_addr = INADDR_ANY; server.sin_port = htons((u_short)portno); /* name the socket */ - if (bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0) + if (bind(x->x_ns.x_sockfd, (struct sockaddr *)&server, sizeof(server)) < 0) { sys_sockerror("bind"); - sys_closesocket(sockfd); - return (0); - } - x = (t_netreceive *)pd_new(netreceive_class); - if (old) - { - /* old style, nonsecure version */ - x->x_msgout = 0; + sys_closesocket(x->x_ns.x_sockfd); + x->x_ns.x_sockfd = -1; + return; } - else x->x_msgout = outlet_new(&x->x_obj, &s_anything); - - x->x_acceptsocket = -1; - if (udp) /* datagram protocol */ + if (x->x_ns.x_protocol == SOCK_DGRAM) /* datagram protocol */ { - t_socketreceiver *y = socketreceiver_new((void *)x, - (t_socketnotifier)netreceive_notify, - (x->x_msgout ? netreceive_doit : 0), 1); - sys_addpollfn(sockfd, (t_fdpollfn)socketreceiver_read, y); - x->x_connectout = 0; + if (x->x_ns.x_bin) + sys_addpollfn(x->x_ns.x_sockfd, (t_fdpollfn)netsend_readbin, x); + else + { + t_socketreceiver *y = socketreceiver_new((void *)x, + (t_socketnotifier)netreceive_notify, + (x->x_ns.x_msgout ? netsend_doit : 0), 1); + sys_addpollfn(x->x_ns.x_sockfd, (t_fdpollfn)socketreceiver_read, y); + x->x_ns.x_connectout = 0; + } } else /* streaming protocol */ { - if (listen(sockfd, 5) < 0) + if (listen(x->x_ns.x_sockfd, 5) < 0) { sys_sockerror("listen"); - sys_closesocket(sockfd); - sockfd = -1; + sys_closesocket(x->x_ns.x_sockfd); + x->x_ns.x_sockfd = -1; } else { - sys_addpollfn(sockfd, (t_fdpollfn)netreceive_connectpoll, x); - x->x_connectout = outlet_new(&x->x_obj, &s_float); + sys_addpollfn(x->x_ns.x_sockfd, (t_fdpollfn)netreceive_connectpoll, x); + x->x_ns.x_connectout = outlet_new(&x->x_ns.x_obj, &s_float); } } - x->x_connectsocket = sockfd; - x->x_nconnections = 0; - x->x_udp = udp; +} - return (x); + +static void netreceive_send(t_netreceive *x, + t_symbol *s, int argc, t_atom *argv) +{ + int i; + for (i = 0; i < x->x_nconnections; i++) + { + if (netsend_dosend(&x->x_ns, x->x_connections[i], s, argc, argv)) + pd_error(x, "netreceive send message failed"); + /* should we now close the connection? */ + } } -static void netreceive_free(t_netreceive *x) +static void *netreceive_new(t_symbol *s, int argc, t_atom *argv) { - /* LATER make me clean up open connections */ - if (x->x_connectsocket >= 0) + t_netreceive *x = (t_netreceive *)pd_new(netreceive_class); + int portno = 0; + x->x_ns.x_protocol = SOCK_STREAM; + x->x_old = 0; + x->x_ns.x_bin = 0; + x->x_nconnections = 0; + x->x_connections = (int *)t_getbytes(0); + x->x_ns.x_sockfd = -1; + if (argc && argv->a_type == A_FLOAT) { - sys_rmpollfn(x->x_connectsocket); - if (x->x_acceptsocket >= 0) - sys_rmpollfn(x->x_acceptsocket); - sys_closesocket(x->x_connectsocket); + portno = atom_getfloatarg(0, argc, argv); + x->x_ns.x_protocol = (atom_getfloatarg(1, argc, argv) != 0 ? + SOCK_DGRAM : SOCK_STREAM); + x->x_old = (!strcmp(atom_getsymbolarg(2, argc, argv)->s_name, "old")); + argc = 0; } + else + { + while (argc && argv->a_type == A_SYMBOL && + *argv->a_w.w_symbol->s_name == '-') + { + if (!strcmp(argv->a_w.w_symbol->s_name, "-b")) + x->x_ns.x_bin = 1; + else if (!strcmp(argv->a_w.w_symbol->s_name, "-u")) + x->x_ns.x_protocol = SOCK_DGRAM; + else + { + pd_error(x, "netreceive: unknown flag ..."); + postatom(argc, argv); endpost(); + } + argc--; argv++; + } + } + if (argc && argv->a_type == A_FLOAT) + portno = argv->a_w.w_float, argc--, argv++; + if (argc) + { + pd_error(x, "netreceive: extra arguments ignored:"); + postatom(argc, argv); endpost(); + } + if (x->x_old) + { + /* old style, nonsecure version */ + x->x_ns.x_msgout = 0; + } + else x->x_ns.x_msgout = outlet_new(&x->x_ns.x_obj, &s_anything); + /* create a socket */ + if (portno > 0) + netreceive_listen(x, portno); + + return (x); } static void netreceive_setup(void) { netreceive_class = class_new(gensym("netreceive"), - (t_newmethod)netreceive_new, (t_method)netreceive_free, - sizeof(t_netreceive), CLASS_NOINLET, A_DEFFLOAT, A_DEFFLOAT, - A_DEFSYM, 0); + (t_newmethod)netreceive_new, (t_method)netreceive_closeall, + sizeof(t_netreceive), 0, A_GIMME, 0); + class_addmethod(netreceive_class, (t_method)netreceive_listen, + gensym("listen"), A_FLOAT, 0); + class_addmethod(netreceive_class, (t_method)netreceive_send, + gensym("send"), A_GIMME, 0); } void x_net_setup(void) diff --git a/pd/src/x_qlist.c b/pd/src/x_qlist.c deleted file mode 100644 index a2300b8776d4b3910f6294d1b167c51385991142..0000000000000000000000000000000000000000 --- a/pd/src/x_qlist.c +++ /dev/null @@ -1,346 +0,0 @@ -/* Copyright (c) 1997-1999 Miller Puckette and others. -* For information on usage and redistribution, and for a DISCLAIMER OF ALL -* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ - -#include "config.h" - -#include "m_pd.h" -#include <string.h> - -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif - -#ifdef HAVE_IO_H -#include <io.h> -#endif - -typedef struct _qlist -{ - t_object x_ob; - t_outlet *x_bangout; - void *x_binbuf; - int x_onset; /* playback position */ - t_clock *x_clock; - t_float x_tempo; - double x_whenclockset; - t_float x_clockdelay; - t_symbol *x_dir; - t_canvas *x_canvas; - int x_reentered; -} t_qlist; - -static void qlist_tick(t_qlist *x); - -static t_class *qlist_class; - -static void *qlist_new( void) -{ - t_qlist *x = (t_qlist *)pd_new(qlist_class); - x->x_binbuf = binbuf_new(); - x->x_clock = clock_new(x, (t_method)qlist_tick); - outlet_new(&x->x_ob, &s_list); - x->x_bangout = outlet_new(&x->x_ob, &s_bang); - x->x_onset = 0x7fffffff; - x->x_tempo = 1; - x->x_whenclockset = 0; - x->x_clockdelay = 0; - x->x_canvas = canvas_getcurrent(); - x->x_reentered = 0; - return (x); -} - -static void qlist_rewind(t_qlist *x) -{ - x->x_onset = 0; - if (x->x_clock) clock_unset(x->x_clock); - x->x_whenclockset = 0; - x->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->x_binbuf), - count, onset = x->x_onset, onset2, wasreentered; - t_atom *argv = binbuf_getvec(x->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->x_onset = onset2; - if (automatic) - { - clock_delay(x->x_clock, - x->x_clockdelay = ap->a_w.w_float * x->x_tempo); - x->x_whenclockset = clock_getsystime(); - } - else outlet_list(x->x_ob.ob_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->x_onset = onset2; - count = onset2 - onset; - if (!target) - { - if (ap->a_type != A_SYMBOL) continue; - else if (!(target = ap->a_w.w_symbol->s_thing)) - { - pd_error(x, "qlist: %s: no such object", - ap->a_w.w_symbol->s_name); - continue; - } - ap++; - onset++; - count--; - if (!count) - { - x->x_onset = onset2; - continue; - } - } - wasreentered = x->x_reentered; - x->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_w.w_symbol, count-1, ap+1); - } - if (x->x_reentered) - return; - x->x_reentered = wasreentered; - } /* while (1); never falls through */ - -end: - x->x_onset = 0x7fffffff; - outlet_bang(x->x_bangout); - x->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->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->x_binbuf, ac, av); - binbuf_add(x->x_binbuf, 1, &a); -} - -static void qlist_add2(t_qlist *x, t_symbol *s, int ac, t_atom *av) -{ - binbuf_add(x->x_binbuf, ac, av); -} - -static void qlist_clear(t_qlist *x) -{ - qlist_rewind(x); - binbuf_clear(x->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->s_name, "cr")) - cr = 1; - else if (*format->s_name) - pd_error(x, "qlist_read: unknown flag: %s", format->s_name); - - if (binbuf_read_via_canvas(x->x_binbuf, filename->s_name, x->x_canvas, cr)) - pd_error(x, "%s: read failed", filename->s_name); - x->x_onset = 0x7fffffff; - x->x_reentered = 1; -} - -static void qlist_write(t_qlist *x, t_symbol *filename, t_symbol *format) -{ - int cr = 0; - char buf[MAXPDSTRING]; - canvas_makefilename(x->x_canvas, filename->s_name, - buf, MAXPDSTRING); - if (!strcmp(format->s_name, "cr")) - cr = 1; - else if (*format->s_name) - pd_error(x, "qlist_read: unknown flag: %s", format->s_name); - if (binbuf_write(x->x_binbuf, buf, "", cr)) - pd_error(x, "%s: write failed", filename->s_name); -} - -static void qlist_print(t_qlist *x) -{ - post("--------- textfile or qlist contents: -----------"); - binbuf_print(x->x_binbuf); -} - -static void qlist_tempo(t_qlist *x, t_float f) -{ - t_float newtempo; - if (f < 1e-20) f = 1e-20; - else if (f > 1e20) f = 1e20; - newtempo = 1./f; - if (x->x_whenclockset != 0) - { - t_float elapsed = clock_gettimesince(x->x_whenclockset); - t_float left = x->x_clockdelay - elapsed; - if (left < 0) left = 0; - left *= newtempo / x->x_tempo; - clock_delay(x->x_clock, left); - } - x->x_tempo = newtempo; -} - -static void qlist_free(t_qlist *x) -{ - binbuf_free(x->x_binbuf); - if (x->x_clock) clock_free(x->x_clock); -} - -/* -------------------- textfile ------------------------------- */ - -static t_class *textfile_class; -typedef t_qlist t_textfile; - -static void *textfile_new( void) -{ - t_textfile *x = (t_textfile *)pd_new(textfile_class); - x->x_binbuf = binbuf_new(); - outlet_new(&x->x_ob, &s_list); - x->x_bangout = outlet_new(&x->x_ob, &s_bang); - x->x_onset = 0x7fffffff; - x->x_reentered = 0; - x->x_tempo = 1; - x->x_whenclockset = 0; - x->x_clockdelay = 0; - x->x_clock = NULL; - x->x_canvas = canvas_getcurrent(); - return (x); -} - -static void textfile_bang(t_textfile *x) -{ - int argc = binbuf_getnatom(x->x_binbuf), onset = x->x_onset, onset2; - t_atom *argv = binbuf_getvec(x->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->x_onset = onset2; - if (ap->a_type == A_SYMBOL) - outlet_anything(x->x_ob.ob_outlet, ap->a_w.w_symbol, - onset2-onset-1, ap+1); - else outlet_list(x->x_ob.ob_outlet, 0, onset2-onset, ap); - } - else - { - x->x_onset = 0x7fffffff; - outlet_bang(x->x_bangout); - } -} - -static void textfile_rewind(t_qlist *x) -{ - x->x_onset = 0; -} - -static void textfile_free(t_textfile *x) -{ - binbuf_free(x->x_binbuf); -} - -/* ---------------- global setup function -------------------- */ - -void x_qlist_setup(void ) -{ - qlist_class = class_new(gensym("qlist"), (t_newmethod)qlist_new, - (t_method)qlist_free, sizeof(t_qlist), 0, 0); - class_addmethod(qlist_class, (t_method)qlist_rewind, gensym("rewind"), 0); - class_addmethod(qlist_class, (t_method)qlist_next, - gensym("next"), A_DEFFLOAT, 0); - class_addmethod(qlist_class, (t_method)qlist_set, gensym("set"), - A_GIMME, 0); - class_addmethod(qlist_class, (t_method)qlist_clear, gensym("clear"), 0); - class_addmethod(qlist_class, (t_method)qlist_add, gensym("add"), - A_GIMME, 0); - class_addmethod(qlist_class, (t_method)qlist_add2, gensym("add2"), - A_GIMME, 0); - class_addmethod(qlist_class, (t_method)qlist_add, gensym("append"), - A_GIMME, 0); - class_addmethod(qlist_class, (t_method)qlist_read, gensym("read"), - A_SYMBOL, A_DEFSYM, 0); - class_addmethod(qlist_class, (t_method)qlist_write, gensym("write"), - A_SYMBOL, A_DEFSYM, 0); - class_addmethod(qlist_class, (t_method)qlist_print, gensym("print"), - A_DEFSYM, 0); - class_addmethod(qlist_class, (t_method)qlist_tempo, - gensym("tempo"), A_FLOAT, 0); - class_addbang(qlist_class, qlist_bang); - - textfile_class = class_new(gensym("textfile"), (t_newmethod)textfile_new, - (t_method)textfile_free, sizeof(t_textfile), 0, 0); - class_addmethod(textfile_class, (t_method)textfile_rewind, gensym("rewind"), - 0); - class_addmethod(textfile_class, (t_method)qlist_set, gensym("set"), - A_GIMME, 0); - class_addmethod(textfile_class, (t_method)qlist_clear, gensym("clear"), 0); - class_addmethod(textfile_class, (t_method)qlist_add, gensym("add"), - A_GIMME, 0); - class_addmethod(textfile_class, (t_method)qlist_add2, gensym("add2"), - A_GIMME, 0); - class_addmethod(textfile_class, (t_method)qlist_add, gensym("append"), - A_GIMME, 0); - class_addmethod(textfile_class, (t_method)qlist_read, gensym("read"), - A_SYMBOL, A_DEFSYM, 0); - class_addmethod(textfile_class, (t_method)qlist_write, gensym("write"), - A_SYMBOL, A_DEFSYM, 0); - class_addmethod(textfile_class, (t_method)qlist_print, gensym("print"), - A_DEFSYM, 0); - class_addbang(textfile_class, textfile_bang); -} - diff --git a/pd/src/x_time.c b/pd/src/x_time.c index 5dc9d37ffeda5b2b867b379b6b73aba4206b2c08..66ce261b2974ae0350a5eb2cf6f99465181c91ff 100644 --- a/pd/src/x_time.c +++ b/pd/src/x_time.c @@ -6,6 +6,60 @@ #include "m_pd.h" #include <stdio.h> +#include <string.h> + + /* parse a time unit such as "5 msec", "60 perminute", or "1 sample" to + a form usable by clock_setunit)( and clock_gettimesincewithunits(). + This brute-force search through symbols really ought not to be done on + the fly for incoming 'tempo' messages, hmm... This isn't public because + its interface migth want to change - but it's used in x_text.c as well + as here. */ +void parsetimeunits(void *x, t_float amount, t_symbol *unitname, + t_float *unit, int *samps) +{ + char *s = unitname->s_name; + if (amount <= 0) + amount = 1; + if (s[0] == 'p' && s[1] == 'e' && s[2] == 'r') /* starts with 'per' */ + { + char *s2 = s+3; + if (!strcmp(s2, "millisecond") || !strcmp(s2, "msec")) /* msec */ + *samps = 0, *unit = 1./amount; + else if (!strncmp(s2, "sec", 3)) /* seconds */ + *samps = 0, *unit = 1000./amount; + else if (!strncmp(s2, "min", 3)) /* minutes */ + *samps = 0, *unit = 60000./amount; + else if (!strncmp(s2, "sam", 3)) /* samples */ + *samps = 1, *unit = 1./amount; + else goto fail; + } + else + { + /* empty string defaults to msec */ + if (!strcmp(s, "millisecond") || !strcmp(s, "msec")) + *samps = 0, *unit = amount; + else if (!strncmp(s, "sec", 3)) + *samps = 0, *unit = 1000.*amount; + else if (!strncmp(s, "min", 3)) + *samps = 0, *unit = 60000.*amount; + else if (!strncmp(s, "sam", 3)) + *samps = 1, *unit = amount; + else + { + fail: + /* empty time unit specification defaults to 1 msec for + back compatibility, since it's possible someone threw a + float argument to timer which had previously been ignored. */ + if (*s) + pd_error(x, "%s: unknown time unit", s); + else pd_error(x, + "tempo setting needs time unit ('sec', 'samp', 'permin', etc."); + *unit = 1; + *samps = 0; + } + } +} + /* -------------------------- delay ------------------------------ */ static t_class *delay_class; @@ -16,6 +70,17 @@ typedef struct _delay double x_deltime; } t_delay; +static void delay_ft1(t_delay *x, t_floatarg g) +{ + if (g < 0) g = 0; + x->x_deltime = g; +} + +static void delay_tick(t_delay *x) +{ + outlet_bang(x->x_obj.ob_outlet); +} + static void delay_bang(t_delay *x) { clock_delay(x->x_clock, x->x_deltime); @@ -26,21 +91,18 @@ static void delay_stop(t_delay *x) clock_unset(x->x_clock); } -static void delay_ft1(t_delay *x, t_floatarg g) -{ - if (g < 0) g = 0; - x->x_deltime = 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) +static void delay_tempo(t_delay *x, t_symbol *unitname, t_floatarg tempo) { - outlet_bang(x->x_obj.ob_outlet); + t_float unit; + int samps; + parsetimeunits(x, tempo, unitname, &unit, &samps); + clock_setunit(x->x_clock, unit, samps); } static void delay_free(t_delay *x) @@ -48,25 +110,31 @@ static void delay_free(t_delay *x) clock_free(x->x_clock); } -static void *delay_new(t_floatarg f) +static void *delay_new(t_symbol *unitname, t_floatarg f, t_floatarg tempo) { t_delay *x = (t_delay *)pd_new(delay_class); delay_ft1(x, f); x->x_clock = clock_new(x, (t_method)delay_tick); outlet_new(&x->x_obj, gensym("bang")); inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft1")); + if (tempo != 0) + delay_tempo(x, unitname, tempo); return (x); } static void delay_setup(void) { delay_class = class_new(gensym("delay"), (t_newmethod)delay_new, - (t_method)delay_free, sizeof(t_delay), 0, A_DEFFLOAT, 0); - class_addcreator((t_newmethod)delay_new, gensym("del"), A_DEFFLOAT, 0); + (t_method)delay_free, sizeof(t_delay), 0, + A_DEFFLOAT, A_DEFFLOAT, A_DEFSYM, 0); + class_addcreator((t_newmethod)delay_new, gensym("del"), + A_DEFFLOAT, A_DEFFLOAT, A_DEFSYM, 0); class_addbang(delay_class, delay_bang); class_addmethod(delay_class, (t_method)delay_stop, gensym("stop"), 0); class_addmethod(delay_class, (t_method)delay_ft1, gensym("ft1"), A_FLOAT, 0); + class_addmethod(delay_class, (t_method)delay_tempo, + gensym("tempo"), A_FLOAT, A_SYMBOL, 0); class_addfloat(delay_class, (t_method)delay_float); } @@ -81,6 +149,13 @@ typedef struct _metro int x_hit; } t_metro; +static void metro_ft1(t_metro *x, t_floatarg g) +{ + if (g <= 0) /* as of 0.45, we're willing to try any positive time value */ + g = 1; /* but default to 1 (arbitrary and probably not so good) */ + x->x_deltime = g; +} + static void metro_tick(t_metro *x) { x->x_hit = 0; @@ -105,10 +180,12 @@ static void metro_stop(t_metro *x) metro_float(x, 0); } -static void metro_ft1(t_metro *x, t_floatarg g) +static void metro_tempo(t_metro *x, t_symbol *unitname, t_floatarg tempo) { - if (g < 1) g = 1; - x->x_deltime = g; + t_float unit; + int samps; + parsetimeunits(x, tempo, unitname, &unit, &samps); + clock_setunit(x->x_clock, unit, samps); } static void metro_free(t_metro *x) @@ -116,7 +193,7 @@ static void metro_free(t_metro *x) clock_free(x->x_clock); } -static void *metro_new(t_floatarg f) +static void *metro_new(t_symbol *unitname, t_floatarg f, t_floatarg tempo) { t_metro *x = (t_metro *)pd_new(metro_class); metro_ft1(x, f); @@ -124,21 +201,27 @@ static void *metro_new(t_floatarg f) x->x_clock = clock_new(x, (t_method)metro_tick); outlet_new(&x->x_obj, gensym("bang")); inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft1")); + if (tempo != 0) + metro_tempo(x, unitname, tempo); return (x); } static void metro_setup(void) { metro_class = class_new(gensym("metro"), (t_newmethod)metro_new, - (t_method)metro_free, sizeof(t_metro), 0, A_DEFFLOAT, 0); + (t_method)metro_free, sizeof(t_metro), 0, + A_DEFFLOAT, A_DEFFLOAT, A_DEFSYM, 0); class_addbang(metro_class, metro_bang); class_addmethod(metro_class, (t_method)metro_stop, gensym("stop"), 0); class_addmethod(metro_class, (t_method)metro_ft1, gensym("ft1"), A_FLOAT, 0); + class_addmethod(metro_class, (t_method)metro_tempo, + gensym("tempo"), A_FLOAT, A_SYMBOL, 0); class_addfloat(metro_class, (t_method)metro_float); } /* -------------------------- line ------------------------------ */ +#define DEFAULTLINEGRAIN 20 static t_class *line_class; typedef struct _line @@ -168,6 +251,8 @@ static void line_tick(t_line *x) outlet_float(x->x_obj.ob_outlet, x->x_setval + x->x_1overtimediff * (timenow - x->x_prevtime) * (x->x_targetval - x->x_setval)); + if (x->x_grain <= 0) + x->x_grain = DEFAULTLINEGRAIN; clock_delay(x->x_clock, (x->x_grain > msectogo ? msectogo : x->x_grain)); } @@ -188,9 +273,11 @@ static void line_float(t_line *x, t_float f) line_tick(x); x->x_gotinlet = 0; x->x_1overtimediff = 1./ (x->x_targettime - timenow); + if (x->x_grain <= 0) + x->x_grain = DEFAULTLINEGRAIN; clock_delay(x->x_clock, (x->x_grain > x->x_in1val ? x->x_in1val : x->x_grain)); - + } else { @@ -232,10 +319,10 @@ static void *line_new(t_floatarg f, t_floatarg grain) x->x_1overtimediff = 1; x->x_clock = clock_new(x, (t_method)line_tick); x->x_targettime = x->x_prevtime = clock_getsystime(); - if (grain <= 0) grain = 20; x->x_grain = grain; outlet_new(&x->x_obj, gensym("float")); inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft1")); + floatinlet_new(&x->x_obj, &x->x_grain); return (x); } @@ -259,33 +346,53 @@ typedef struct _timer { t_object x_obj; double x_settime; + double x_moreelapsed; + t_float x_unit; + int x_samps; } t_timer; static void timer_bang(t_timer *x) { x->x_settime = clock_getsystime(); + x->x_moreelapsed = 0; } static void timer_bang2(t_timer *x) { - outlet_float(x->x_obj.ob_outlet, clock_gettimesince(x->x_settime)); + outlet_float(x->x_obj.ob_outlet, + clock_gettimesincewithunits(x->x_settime, x->x_unit, x->x_samps) + + x->x_moreelapsed); +} + +static void timer_tempo(t_timer *x, t_symbol *unitname, t_floatarg tempo) +{ + x->x_moreelapsed += clock_gettimesincewithunits(x->x_settime, + x->x_unit, x->x_samps); + x->x_settime = clock_getsystime(); + parsetimeunits(x, tempo, unitname, &x->x_unit, &x->x_samps); } -static void *timer_new(t_floatarg f) +static void *timer_new(t_symbol *unitname, t_floatarg tempo) { t_timer *x = (t_timer *)pd_new(timer_class); + x->x_unit = 1; + x->x_samps = 0; timer_bang(x); outlet_new(&x->x_obj, gensym("float")); inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("bang"), gensym("bang2")); + if (tempo != 0) + timer_tempo(x, unitname, tempo); return (x); } static void timer_setup(void) { timer_class = class_new(gensym("timer"), (t_newmethod)timer_new, 0, - sizeof(t_timer), 0, A_DEFFLOAT, 0); + sizeof(t_timer), 0, A_DEFFLOAT, A_DEFSYM, 0); class_addbang(timer_class, timer_bang); class_addmethod(timer_class, (t_method)timer_bang2, gensym("bang2"), 0); + class_addmethod(timer_class, (t_method)timer_tempo, + gensym("tempo"), A_FLOAT, A_SYMBOL, 0); } @@ -419,7 +526,7 @@ static void hang_tick(t_hang *h) int i; union word *w; if (x->x_hang == h) x->x_hang = h->h_next; - else for (h2 = x->x_hang; h3 = h2->h_next; h2 = h3) + else for (h2 = x->x_hang; (h3 = h2->h_next); h2 = h3) { if (h3 == h) { @@ -439,6 +546,7 @@ static void hang_tick(t_hang *h) outlet_pointer(p->p_outlet, w->w_gpointer); else pd_error(x, "pipe: stale pointer"); break; + default: break; } } hang_free(h); @@ -478,6 +586,7 @@ static void pipe_list(t_pipe *x, t_symbol *s, int ac, t_atom *av) if (gp->gp_stub) gp->gp_stub->gs_refcount++; } gp++; + default: break; } } for (i = 0, gp = x->x_gp, gp2 = h->h_gp, p = x->x_vec, w = h->h_vec; @@ -506,17 +615,23 @@ static void pipe_flush(t_pipe *x) static void pipe_clear(t_pipe *x) { t_hang *hang; - while (hang = x->x_hang) + while ((hang = x->x_hang)) { x->x_hang = hang->h_next; hang_free(hang); } } +static void pipe_free(t_pipe *x) +{ + pipe_clear(x); + freebytes(x->x_vec, x->x_n * sizeof(*x->x_vec)); +} + static void pipe_setup(void) { - pipe_class = class_new(gensym("pipe"), - (t_newmethod)pipe_new, (t_method)pipe_clear, + pipe_class = class_new(gensym("pipe"), + (t_newmethod)pipe_new, (t_method)pipe_free, sizeof(t_pipe), 0, A_GIMME, 0); class_addlist(pipe_class, pipe_list); class_addmethod(pipe_class, (t_method)pipe_flush, gensym("flush"), 0);