Hey,
We talked about this in the recent past. Could someone who knows the details remove the declarations of the string type from branches/pd- extended/0.40? Or shall I just remove the whole patch? I want to include string support, but using the technique that IOhannes laid out, which should be possible without patching Pd (AFAIK).
.hc
------------------------------------------------------------------------ ----
Using ReBirth is like trying to play an 808 with a long stick. - David Zicarelli
Could someone point me to IOhannes' technique? If it makes sense I'll give it a go during the next week.
Martin
From: Hans-Christoph Steiner hans@eds.org To: pd-dev List pd-dev@iem.at Subject: [PD-dev] removing string types from pd-extended release Date: Thu, 8 May 2008 20:44:09 +0200
Hey,
We talked about this in the recent past. Could someone who knows the details remove the declarations of the string type from branches/pd- extended/0.40? Or shall I just remove the whole patch? I want to include string support, but using the technique that IOhannes laid out, which should be possible without patching Pd (AFAIK).
.hc
Using ReBirth is like trying to play an 808 with a long stick. - David Zicarelli
PD-dev mailing list PD-dev@iem.at http://lists.puredata.info/listinfo/pd-dev
I don't know the details, but I believe it was just choosing an unused number to represent the type. Then also not using a keyword. Ultimately, there could be something like /etc/services where we can register these numbers. Or maybe they could just be included in the Pd headers.
http://lists.puredata.info/pipermail/pd-dev/2008-04/011257.html
.hc
On May 8, 2008, at 10:33 PM, Martin Peach wrote:
Could someone point me to IOhannes' technique? If it makes sense I'll give it a go during the next week.
Martin
From: Hans-Christoph Steiner hans@eds.org To: pd-dev List pd-dev@iem.at Subject: [PD-dev] removing string types from pd-extended release Date: Thu, 8 May 2008 20:44:09 +0200
Hey,
We talked about this in the recent past. Could someone who knows the details remove the declarations of the string type from branches/pd- extended/0.40? Or shall I just remove the whole patch? I want to include string support, but using the technique that IOhannes laid out, which should be possible without patching Pd (AFAIK).
.hc
Using ReBirth is like trying to play an 808 with a long stick. - David Zicarelli
PD-dev mailing list PD-dev@iem.at http://lists.puredata.info/listinfo/pd-dev
------------------------------------------------------------------------ ----
All information should be free. - the hacker ethic
I've attached the reasoning behind my string patch, probably there is a lot wrong with it.
But I can't see how to do this kind of thing otherwise without modifying Pd.
Martin
Hans-Christoph Steiner wrote:
I don't know the details, but I believe it was just choosing an unused number to represent the type. Then also not using a keyword. Ultimately, there could be something like /etc/services where we can register these numbers. Or maybe they could just be included in the Pd headers.
http://lists.puredata.info/pipermail/pd-dev/2008-04/011257.html
.hc
On May 8, 2008, at 10:33 PM, Martin Peach wrote:
Could someone point me to IOhannes' technique? If it makes sense I'll give it a go during the next week.
Martin
From: Hans-Christoph Steiner hans@eds.org To: pd-dev List pd-dev@iem.at Subject: [PD-dev] removing string types from pd-extended release Date: Thu, 8 May 2008 20:44:09 +0200
Hey,
We talked about this in the recent past. Could someone who knows the details remove the declarations of the string type from branches/pd- extended/0.40? Or shall I just remove the whole patch? I want to include string support, but using the technique that IOhannes laid out, which should be possible without patching Pd (AFAIK).
.hc
Using ReBirth is like trying to play an 808 with a long stick. - David Zicarelli
PD-dev mailing list PD-dev@iem.at http://lists.puredata.info/listinfo/pd-dev
All information should be free. - the hacker ethic
PD-dev mailing list PD-dev@iem.at http://lists.puredata.info/listinfo/pd-dev
I think it would be most efficient to have a string type be a length followed by that many unsigned chars, similar to a Pascal string but with the length being something like a 32-bit integer. It would not be added to pd's symbol list. The atom whose type was string would have to contain a pointer to the first byte of the string, and a length. Multibyte characters would just be counted as multiple characters when calculating the length, so the length would be the number of bytes in the string, not the number of characters. It looks too easy to me...In m_pd.h, add: A_STRING to t_atomtype at line 139 of m_pd.h. Add t_string * w_string; to t_word at line 122 of m_pd.h. Add the typedef: typedef struct _string /* pointer to a string */ { unsigned long s_length; /* length of string in bytes */ unsigned char *s_data; /* pointer to 1st byte of string */ } t_string; at line 106 of m_pd.h ...so a string atom would have a_type = A_STRING and a_w = a_w.w_string, which points to a t_string containing the length and a pointer to the string.
This we did first and now we are compiling pd on linux to see if it breaks anything...not so far.
If pd is otherwise able to handle atom types it doesn't know about (?), all the string manipulation objects could be built as externals.
As I see it the atom types are defined in m_pd.h and registered in m_class.c, which would need to have functions added to it to handle string, like adding: t_symbol s_string = {"string", 0, 0}; to the list of t_symbols around line 555, and changing: static t_symbol *symlist[] = { &s_pointer, &s_float, &s_symbol, &s_bang, &s_list, &s_anything, &s_signal, &s__N, &s__X, &s_x, &s_y, &s_}; to: static t_symbol *symlist[] = { &s_pointer, &s_float, &s_symbol, &s_bang, &s_list, &s_anything, &s_signal, &s__N, &s__X, &s_x, &s_y, &s_, &s_string}; ...and pd_typedmess needs a handler for string messages around line 658: if (s == &s_string) { if (argc == 1) (*c->c_stringmethod)(x, argv->a_w.w_string); else goto badarg; return; } ...and a handler for messages with string arguments with other names, just befor case A_SYMBOL, line 728: case A_STRING:/* MP 20070106 string type */ post("pd_typedmess A_STRING"); if (!argc) goto badarg; if (argv->a_type == A_STRING) { post("argv->a_type == A_STRING, argc = %d, narg= %d", argc, narg); *ap = (t_int)(argv->a_w.w_string); mp = 1; } argc--; argv++; narg++; ap++; break;
Still in m_class.c, around line 344 we add: void class_addstring(t_class *c, t_method fn) { c->c_stringmethod = (t_stringmethod)fn; } This is used to register a string handler with pd so that incoming strings will be sent to fn. We added: else if (sel == &s_string) /* MP 20070106 string type */ { post("class_addmethod: %p", fn); if (argtype != A_STRING || va_arg(ap, t_atomtype)) goto phooey; class_addstring(c, fn); } around line 300 of m_class.c in case someone calls class_addmethod instead of class_addstring with a string selector.
Then in m_pd.h, line 418: EXTERN void class_addstring(t_class *c, t_method fn); and at line 447: #define class_addstring(x, y) class_addstring((x), (t_method)(y)) Also add: EXTERN t_symbol s_string; at line 226 of m_pd.h.
In m_imp.h we need to define the stringmethod function at line 28: typedef void (*t_stringmethod)(t_pd *x, t_string *st); and, inside struct _class we add a place to store a pointer to the stringmethod at line 45: t_stringmethod c_stringmethod; . As long as no externals are accessing struct _class directly, this should be safe.
Add to m_pd.c, line 287 the function to be called when a string arrives at an inlet: void pd_string(t_pd *x, t_string *st) { (*(*x)->c_stringmethod)(x, st); } We need to add a prototype for pd_string in m_pd.h at line 340ish: EXTERN void pd_string(t_pd *x, t_string *st);
Along the lines of pd_defaultlist() in m_class.c, which handles list messages for objects that don't have list methods, one could add a pd_defaultstring(), which attempts to convert strings into symbols/floats/lists, instead of calling pd_defaultanything(), which would print "no method for string". But it needs to be understood that it might not do it correctly, which is Not A Good Thing, but no worse than comments getting mangled. Maybe a [string unpack] object would be better: it could attempt to unpack a string into specified types, so the user could decide if a string like "123" is meant to represent a float or a symbol.
In class_new() in m_class.c we add: static void pd_defaultstring(t_pd *x, t_string *st); around line 22, c->c_stringmethod = pd_defaultstring; at line 208. Add static void pd_defaultstring(t_pd *x, t_string *st) { /* for now just reject it, later convert to symbol/float/list */ pd_error(x, "%s: no method for string so far...", (*x)->c_name->s_name); } around line 40.
And now outlets: Add to m_pd.h, line 364ish: EXTERN void outlet_string(t_outlet *x, t_string *st); This will send a string through an outlet, by calling the pd_string method on all the inlets connected to the outlet. It's defined in m_obj.c, line 369ish: void outlet_string(t_outlet *x, t_string *st) { t_outconnect *oc; if(++stackcount >= STACKITER) outlet_stackerror(x); else for (oc = x->o_connections; oc; oc = oc->oc_next) pd_string(oc->oc_to, st); --stackcount; } We defined pd_string in m_pd.c. To add a string-capable outlet to an object, we already have outlet_new() in m_obj.c.
And inlets: static void inlet_string(t_inlet *x, t_string *st) { if (x->i_symfrom == &s_string) pd_vmess(x->i_dest, x->i_symto, "t", st); else if (!x->i_symfrom) pd_string(x->i_dest, st); else inlet_wrong(x, &s_string); } should be added around line 113 of m_obj.c. What is x->i_symfrom? It is equal to s_string if the inlet is string-capable. See stringinlet_new, below. When is it equal to zero?
Also in m_obj.c, obj_init needs a line around 255: class_addstring(inlet_class, inlet_string); In m_class.c, line 794ish we add the line: case 't': SETSTRING(at, va_arg(ap, t_string *)); break; to pd_vmess. Now we need to add SETSTRING to m_pd.h, line 267ish: #define SETSTRING(atom, st) ((atom)->a_type = A_STRING, (atom)->a_w.w_string = (st))
To be able to add the inlet to an object we need to add this to m_obj.c around line 200: t_inlet *stringinlet_new(t_object *owner, t_string **stp) { t_inlet *x = (t_inlet *)pd_new(stringinlet_class), *y, *y2; x->i_owner = owner; x->i_dest = 0; x->i_symfrom = &s_string; x->i_stringslot = stp; x->i_next = 0; if (y = owner->ob_inlet) { while (y2 = y->i_next) y = y2; y->i_next = x; } else owner->ob_inlet = x; return (x); }
We need to add stringinlet_class at line 37 of m_obj.c: static t_class *inlet_class, *pointerinlet_class, *floatinlet_class, *symbolinlet_class, *stringinlet_class; Also define a stringslot and add it to the union inletunion at line 12 of m_obj.c: union inletunion { t_symbol *iu_symto; t_gpointer *iu_pointerslot; t_float *iu_floatslot; t_symbol **iu_symslot; t_string **iu_stringslot; t_sample iu_floatsignalvalue; }; and at line 35ish: #define i_stringslot i_un.iu_stringslot
Now the only thing that doesn't work properly is messages with strings replacing their $ arguments. For instance, sending [append $1( to a [str join] should set the appended string (also set by the creation argument or the second inlet), but instead gives "no method for string" with a string, and crashes pd with non-string values. Hop on over to g_text.c, where message lives. There's a t_message class: typedef struct _message { t_text m_text; t_messresponder m_messresponder; t_glist *m_glist; t_clock *m_clock; } t_message; ...and a t_messresponder which keeps the message's outlet: typedef struct _messresponder { t_pd mr_pd; t_outlet *mr_outlet; } t_messresponder; The message object is set up in g_text_setup, not message_setup as you might expect. I guess this is to stop a patcher from adding one of these as a [message] object.(?) g_text_setup also sets up messresponder and gatom. Less naively we add: case A_STRING: if (nargs == 1) pd_string(target, stackwas->a_w.w_string); else pd_list(target, 0, nargs, stackwas); after gotmess in m_binbuf.c, line 678ish. This results in pd_string being called when a message receives a string, but because message's string method is default_string, the string doesn't get through. So what we need to do now is set message's string method... At line 1337 of g_text.c add: class_addstring(message_class, message_string); and static void message_string(t_message *x, t_string *st) { t_atom at; SETSTRING(&at, st); binbuf_eval(x->m_text.te_binbuf, &x->m_messresponder.mr_pd, 1, &at); } at line 310.
Now we can send a string to a [set $1( message to [string join] and it will set the append string just as if the string went directly to the second inlet. Unfortunately, other kinds of message will usually crash pd. Probably we need a way to be sure that an [append $1( or [compare $1( message really has a string attached. Or is the fact that we never specified a m_messresponder for string types to blame? We add: static void messresponder_string(t_messresponder *x, t_string *st) { /* MP 20070107 string type */ outlet_string(x->mr_outlet, st); } at line 279 of g_text.c. Same thing happens. Add EXTERN t_string *atom_getstring(t_atom *a); to m_pd.h line 280ish and t_string *atom_getstring(t_atom *a) /* MP 20070108 */ { static unsigned char c = 0;/* a default string to avoid null pointers. This should be somewhere else...? */ static t_string st = {1L, &c}; if (a->a_type == A_STRING) return (a->a_w.w_string); else return (&st); } around line 36 of m_atom.c
All these additions should work without breaking anything else as long as externals access pd only via the functions exposed in m_pd.h. Probably we'll need to add somthing in g_io.c as well...
Martin Peach wrote:
I've attached the reasoning behind my string patch, probably there is a lot wrong with it.
But I can't see how to do this kind of thing otherwise without modifying Pd.
i only proposed to just removed all the selector stuff ("string") and use plain atoms (within lists/messages) instead.
i don't see _any_ reason why we would need to have a "stringmethod" pd knows about. instead use:
<snip> #define STRING_ATOMID=666 static void myobj_string(t_myobj*x, t_symbol*s, int argc, t_atom*argv) { if (argc && STRING_ATOMID==argv->a_type) { // hold on, this is a string! ... } else { pd_error(x, "expected string"); } }
void myobj_setup(void) { ... class_addmethod(myobj_class, (t_method)myobj_string, gensym("string"), A_GIMME, 0); } </snip>
et voila! no need to patch Pd at all.
in a second step, Pd should handle atoms outside its "known" world properly. my initial idea was to introduce a way to register new types with Pd, so pd would know about a new a_type number during runtime and would be able to do handle it more intelligently (e.g. calling a certain atom_getstring() method when [post]ing; rejecting atom-types that it doesn't know about;...)
miller was rather reluctant about this, as it probably adds too much hazzle for too little benefit. therefore we basically agreed (at lac2008) that we would just use additional a_type-numbers and that's basically it!
fgmadsr IOhannes
IOhannes m zmölnig wrote:
#define STRING_ATOMID=666
and while we are at it: i hereby want to claim the atomID "75" for FTMobjects [1]. please do not use this atomID, if you are not wrapping FTMobjects within such atom.
mfasdr IOhannes
IOhannes m zmölnig wrote:
IOhannes m zmölnig wrote:
#define STRING_ATOMID=666
and while we are at it: i hereby want to claim the atomID "75" for FTMobjects [1]. please do not use this atomID, if you are not wrapping FTMobjects within such atom.
additionally, i want to claim atomID "77" for FTMstrings (which are part of ftm, but since i have never used them before, i plainly forgot about them; i also cannot answer any questions on how they actually work and whether they might be compatible with mrpeach's strings)
mfgasdr IOhannes
On Fri, May 9, 2008 at 3:13 AM, IOhannes m zmölnig zmoelnig@iem.at wrote:
IOhannes m zmölnig wrote:
IOhannes m zmölnig wrote:
#define STRING_ATOMID=666
and while we are at it: i hereby want to claim the atomID "75" for FTMobjects [1]. please do not use this atomID, if you are not wrapping FTMobjects within such atom.
additionally, i want to claim atomID "77" for FTMstrings (which are part of ftm, but since i have never used them before, i plainly forgot about them; i also cannot answer any questions on how they actually work and whether they might be compatible with mrpeach's strings)
also, i'd just like to add, that i think the 666 atomID should be reserved for 'evil' data. It could be useful in the future for optimized implementations of evil processing routines.
thanks, Steve
Stephen Sinclair wrote:
also, i'd just like to add, that i think the 666 atomID should be reserved for 'evil' data. It could be useful in the future for optimized implementations of evil processing routines.
you are right; sorry for the confusion with A_BLOB/A_STRING...
time to start a wiki http://puredata.info/docs/developer/AtomTypes
mfgasr IOhannes
On Fri, May 9, 2008 at 11:27 AM, IOhannes m zmölnig zmoelnig@iem.at wrote:
Stephen Sinclair wrote:
also, i'd just like to add, that i think the 666 atomID should be reserved for 'evil' data. It could be useful in the future for optimized implementations of evil processing routines.
you are right; sorry for the confusion with A_BLOB/A_STRING...
time to start a wiki http://puredata.info/docs/developer/AtomTypes
very nice, thanks. :) hopefully it will be useful. (for evil purposes of course.)
steve
On May 9, 2008, at 5:27 PM, IOhannes m zmölnig wrote:
Stephen Sinclair wrote:
also, i'd just like to add, that i think the 666 atomID should be reserved for 'evil' data. It could be useful in the future for optimized implementations of evil processing routines.
you are right; sorry for the confusion with A_BLOB/A_STRING...
time to start a wiki http://puredata.info/docs/developer/AtomTypes
Seems like it would be most useful as a header (.h) file. Perhaps we could just make that page be C header format, with inline comments.
.hc
mfgasr IOhannes
PD-dev mailing list PD-dev@iem.at http://lists.puredata.info/listinfo/pd-dev
------------------------------------------------------------------------ ----
As we enjoy great advantages from inventions of others, we should be glad of an opportunity to serve others by any invention of ours; and this we should do freely and generously. - Benjamin Franklin
On May 10, 2008, at 12:59 PM, Hans-Christoph Steiner wrote:
On May 9, 2008, at 5:27 PM, IOhannes m zmölnig wrote:
Stephen Sinclair wrote:
also, i'd just like to add, that i think the 666 atomID should be reserved for 'evil' data. It could be useful in the future for optimized implementations of evil processing routines.
you are right; sorry for the confusion with A_BLOB/A_STRING...
time to start a wiki http://puredata.info/docs/developer/AtomTypes
Seems like it would be most useful as a header (.h) file. Perhaps we could just make that page be C header format, with inline comments.
Any word on this? This is basically the last thing that needs to be handled before the release.
.hc
.hc
mfgasr IOhannes
PD-dev mailing list PD-dev@iem.at http://lists.puredata.info/listinfo/pd-dev
As we enjoy great advantages from inventions of others, we should be glad of an opportunity to serve others by any invention of ours; and this we should do freely and generously. - Benjamin Franklin
------------------------------------------------------------------------ ----
Access to computers should be unlimited and total. - the hacker ethic
On Fri, 9 May 2008, IOhannes m zmölnig wrote:
Stephen Sinclair wrote:
also, i'd just like to add, that i think the 666 atomID should be reserved for 'evil' data. It could be useful in the future for optimized implementations of evil processing routines.
you are right; sorry for the confusion with A_BLOB/A_STRING... time to start a wiki http://puredata.info/docs/developer/AtomTypes
I edited it quite a bit. Split it in 5 parts total: the normal types, the messagebox-only types, the pseudo-types, the user-defined normal types, and the user-defined pseudo-types.
By pseudo-type I mean something not used in t_atom::a_type.
I added the GF/DD types as well.
_ _ __ ___ _____ ________ _____________ _____________________ ... | Mathieu Bouchard - tél:+1.514.383.3801, Montréal, Québec
On Sat, 28 Jun 2008, Mathieu Bouchard wrote:
I edited it quite a bit. Split it in 5 parts total: the normal types, the messagebox-only types, the pseudo-types, the user-defined normal types, and the user-defined pseudo-types. By pseudo-type I mean something not used in t_atom::a_type. I added the GF/DD types as well.
In addition to reserving A_ATOM (12), A_LIST (13), A_GRID (14), I just added A_GRIDOUT (15).
So far, I already use A_LIST and I'm starting to use A_GRIDOUT right away as a replacement for my bogus use of A_POINTER. The others are for future use. There is a slight possibility of a merge of A_GRID and A_GRIDOUT together eventually, and there's a much bigger possibility of adding extra types for some OpenCV things and such.
_ _ __ ___ _____ ________ _____________ _____________________ ... | Mathieu Bouchard - tél:+1.514.383.3801, Montréal, Québec