Skip to content

Commit 61ad2a3

Browse files
committed
bits and bobs
1 parent 38e6951 commit 61ad2a3

File tree

5 files changed

+142
-17
lines changed

5 files changed

+142
-17
lines changed

README.md

+7-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ editor | read | file | n/a | no | [x]
5151
editor | load | file | yes | no | [x]
5252

5353

54-
### Basic Features
54+
### Key Features
5555

5656
1. **Per-object namespaces**. The `py` object responds to an `import <module>` message in the left inlet which loads a python module in its namespace. Each new import (like python) adds modules to the namespace.
5757

@@ -66,6 +66,11 @@ editor | load | file | yes | no | [x]
6666
6. **Code Editor**. Double-clicking on the object open a code-editor which can have a `read` message which reads a file, specified as an attribute, into the editor, and also a `load` message which `reads` the file and then `execfile` it into the editor.
6767

6868

69+
7. **Exposing Max API to Python** A significant part of the `c74support/max-includes` has been converted to a cython `.pxd` file called `api_max.pxd` and available to `api.pyx` cython module which is converted to c-code and embedded in the external. This enables a custom python builtin module called `api` which can be imported by python scripts in `py` objects and also via `import` messages. What this effectively means is that python scripts in `py` objects can directly call max c-api functions.
70+
71+
8. **Globals Exchange**. The `py` external has special builtin python module called `globex` which exposes globals which can be read and written from the python script side and also from the c external side.
72+
73+
6974

7075
## Building
7176

@@ -158,6 +163,7 @@ The style used in this project is specified in the `.clang-format` file.
158163
## TODO
159164

160165

166+
- [ ] add set/get for attributes as appropriate to trigger actions or methods calls after changes
161167
- [ ] enhance `py_anything` method to eval if identifier exists in ns and is not callable
162168
- [ ] Add file location feature (try pkg/examples/scripts then absolute paths)
163169
```c

help/py.maxhelp

+9-9
Original file line numberDiff line numberDiff line change
@@ -678,7 +678,7 @@
678678
"numinlets" : 2,
679679
"numoutlets" : 1,
680680
"outlettype" : [ "" ],
681-
"patching_rect" : [ 160.0, 393.0, 35.0, 22.0 ],
681+
"patching_rect" : [ 277.5, 325.0, 35.0, 22.0 ],
682682
"text" : "clear"
683683
}
684684

@@ -726,7 +726,7 @@
726726
"maxclass" : "comment",
727727
"numinlets" : 1,
728728
"numoutlets" : 0,
729-
"patching_rect" : [ 197.0, 406.0, 150.0, 60.0 ],
729+
"patching_rect" : [ 13.0, 416.0, 133.0, 60.0 ],
730730
"text" : "test for getting scripting from patcher, name lookup in the global registry and msg send!"
731731
}
732732

@@ -737,7 +737,7 @@
737737
"maxclass" : "comment",
738738
"numinlets" : 1,
739739
"numoutlets" : 0,
740-
"patching_rect" : [ 269.5, 474.0, 150.0, 20.0 ],
740+
"patching_rect" : [ 75.5, 476.0, 99.0, 20.0 ],
741741
"text" : "name: missint"
742742
}
743743

@@ -750,7 +750,7 @@
750750
"numoutlets" : 2,
751751
"outlettype" : [ "", "bang" ],
752752
"parameter_enable" : 0,
753-
"patching_rect" : [ 213.5, 474.0, 50.0, 22.0 ],
753+
"patching_rect" : [ 19.5, 476.0, 50.0, 22.0 ],
754754
"varname" : "missint"
755755
}
756756

@@ -761,7 +761,7 @@
761761
"maxclass" : "comment",
762762
"numinlets" : 1,
763763
"numoutlets" : 0,
764-
"patching_rect" : [ 269.5, 553.5, 150.0, 20.0 ],
764+
"patching_rect" : [ 75.5, 555.5, 83.0, 20.0 ],
765765
"text" : "name: mrmsg"
766766
}
767767

@@ -785,7 +785,7 @@
785785
"numinlets" : 2,
786786
"numoutlets" : 1,
787787
"outlettype" : [ "" ],
788-
"patching_rect" : [ 213.5, 553.5, 50.0, 22.0 ],
788+
"patching_rect" : [ 19.5, 555.5, 50.0, 22.0 ],
789789
"varname" : "mrmsg"
790790
}
791791

@@ -819,7 +819,7 @@
819819
"maxclass" : "comment",
820820
"numinlets" : 1,
821821
"numoutlets" : 0,
822-
"patching_rect" : [ 269.5, 500.0, 142.0, 20.0 ],
822+
"patching_rect" : [ 75.5, 502.0, 99.0, 20.0 ],
823823
"text" : "name: bigbanger"
824824
}
825825

@@ -832,7 +832,7 @@
832832
"numoutlets" : 1,
833833
"outlettype" : [ "bang" ],
834834
"parameter_enable" : 0,
835-
"patching_rect" : [ 213.5, 500.0, 50.0, 50.0 ],
835+
"patching_rect" : [ 19.5, 502.0, 50.0, 50.0 ],
836836
"varname" : "bigbanger"
837837
}
838838

@@ -882,7 +882,7 @@
882882
"numinlets" : 2,
883883
"numoutlets" : 1,
884884
"outlettype" : [ "" ],
885-
"patching_rect" : [ 270.0, 325.0, 29.5, 22.0 ],
885+
"patching_rect" : [ 231.5, 325.0, 29.5, 22.0 ],
886886
"text" : "set"
887887
}
888888

init/py-fileformats.txt

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
max definekind python @parent textfile @showextension 1;
2+
max fileformat .py TEXT 0 "Python Source file" python;

source/py/notes/max-c-api.md

+112
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,60 @@
22
# Max C API Notes
33

44

5+
## Memory management
6+
7+
```c
8+
char *ptr;
9+
char **hand;
10+
ptr = sysmem_newptr(2000);
11+
post("I have a pointer %lx and it is %ld bytes in size",ptr, sysmem_ptrsize(ptr));
12+
ptr = sysmem_resizeptrclear(ptr, 3000);
13+
post("Now I have a pointer %lx and it is %ld bytes in size",ptr,
14+
sysmem_ptrsize(ptr));
15+
sysmem_freeptr(ptr);
16+
hand = sysmem_newhandle(2000);
17+
post("I have a handle %lx and it is %ld bytes in size",hand,
18+
sysmem_handlesize(hand));
19+
sysmem_resizehandle(hand, 3000);
20+
post("Now the handle %lx is %ld bytes in size",hand, sysmem_ptrsize(hand));
21+
sysmem_freehandle(hand);
22+
```
23+
24+
## Typed vs Untyped Methods
25+
26+
27+
28+
29+
30+
31+
32+
33+
34+
35+
This is from the Max API docs:
36+
37+
Max objects, such as the one you write, are C data structures in which methods are dynamically bound to functions. Your object's methods are called by Max, but your object can also call methods itself. When you call a method, it is
38+
essential to know whether the method you are calling is typed or not.
39+
40+
Calling a typed method requires passing arguments as an array of atoms. Calling an untyped method requires that you know the exact arguments of the C function implementing the method. In both cases, you supply a symbol that names the method.
41+
42+
In the typed method case, Max will take the array of atoms and pass the arguments to the object according to the method's argument type specifier list. For example, if the method is declared to have an argument type specifier list of A_LONG, 0, the first atom in the array you pass will be converted to an int and passed to the function on the stack. If there are no arguments supplied, invoking a typed method that has A_LONG, 0 as an argument type specifier will fail. To make typed method calls, use `object_method_typed()` or `typedmess()`.
43+
44+
In the untyped method case, Max merely does a lookup of the symbol in the object, and, if a matching function is found, calls the function with the arguments you pass.
45+
Certain methods you write for your object, such as the assist method for describing your object and the DSP method in audio objects, are declared as untyped using the A_CANT argument type specifier. This means that Max will not typecheck the arguments you pass to these methods, but, most importantly, a user cannot hook up a message box to your object and send it a message to invoke an untyped method. (Try this for yourself – send the assist message to a standard Max object.)
46+
47+
When you use an outlet, you're effectively making a typed method call on any objects connected to the outlet.
48+
49+
50+
51+
552
653
## Sending arbitrary messages to an object
754
55+
56+
57+
58+
859
In https://cycling74.com/forums/error-handling-with-object_method_typed, there is a need to figure the type of the method which is being called in sending.
960
1061
@@ -162,6 +213,67 @@ In this example since the message "clear" has no arguments the typed/untyped dis
162213
163214
### ext_obex.h
164215
216+
For Untyped Methods (A_CANT)
217+
218+
```c
219+
220+
/**
221+
Sends an untyped message to an object.
222+
There are some caveats to its use, however, particularly for 64-bit architectures.
223+
object_method_direct() should be used in cases where floating-point or other non-integer types are being passed on the stack or in return values.
224+
225+
@ingroup obj
226+
227+
@param x The object that will receive the message
228+
@param s The message selector
229+
@param ... Any arguments to the message
230+
231+
@return If the receiver object can respond to the message, object_method() returns the result. Otherwise, the function will return 0.
232+
233+
@remark Example: To send the message <tt>bang</tt> to the object <tt>bang_me</tt>:
234+
@code
235+
void *bang_result;
236+
bang_result = object_method(bang_me, gensym("bang"));
237+
@endcode
238+
*/
239+
240+
void *object_method(void *x, t_symbol *s, ...);
241+
242+
/**
243+
do a strongly typed direct call to a method of an object
244+
245+
@ingroup obj
246+
247+
248+
@param rt The type of the return value (double, void*, void...)
249+
@param sig the actual signature of the function in brackets !
250+
something like (t_object *, double, long)
251+
@param x The object where the method we want to call will be looked for,
252+
it will also always be the first argument to the function call
253+
@param s The message selector
254+
@param ... Any arguments to the call, the first one will always be the object (x)
255+
256+
@return will return anything that the called function returns, typed by (rt)
257+
258+
@remark Example: To call the function identified by <tt>getcolorat</tt> on the object <tt>pwindow</tt>
259+
which is declared like:
260+
t_jrgba pwindow_getcolorat(t_object *window, double x, double y)
261+
@code
262+
double x = 44.73;
263+
double y = 79.21;
264+
t_object *pwindow;
265+
t_jrgba result = object_method_direct(t_jrgba, (t_object *, double, double), pwindow, gensym("getcolorat"), x, y);
266+
@endcode
267+
*/
268+
269+
#define object_method_direct(rt, sig, x, s, ...) ((rt (*)sig)object_method_direct_getmethod((t_object *)x, s))(object_method_direct_getobject((t_object *)x, s), __VA_ARGS__)
270+
271+
method object_method_direct_getmethod(t_object *x, t_symbol *sym);
272+
void *object_method_direct_getobject(t_object *x, t_symbol *sym);
273+
```
274+
275+
276+
For Typed Methods (A_GIMME)
165277
```c
166278
/**
167279
Sends a type-checked message to an object.

source/py/py.c

+12-7
Original file line numberDiff line numberDiff line change
@@ -641,14 +641,19 @@ void py_doread(t_py* x, t_symbol* s, long argc, t_atom* argv)
641641
t_filehandle fh;
642642

643643
if (s == gensym("")) {
644-
if (x->p_code_filepath != gensym("")) {
645-
strcpy(filename, x->p_code_filepath->s_name);
646-
} else {
647-
filename[0] = 0;
648-
if (open_dialog(filename, &path, &type, &type, 1))
649-
x->p_code_filepath = gensym(filename);
644+
filename[0] = 0;
645+
646+
if (open_dialog(filename, &path, &type, &type, 1))
650647
return;
651-
}
648+
649+
// if (x->p_code_filepath != gensym("")) {
650+
// strcpy(filename, x->p_code_filepath->s_name);
651+
// } else {
652+
// filename[0] = 0;
653+
// if (open_dialog(filename, &path, &type, &type, 1))
654+
// x->p_code_filepath = gensym(filename);
655+
// return;
656+
// }
652657
} else {
653658
strcpy(filename, s->s_name);
654659
x->p_code_filepath = s;

0 commit comments

Comments
 (0)