Jamoma API  0.6.0.a19
Max/source/j.modular/j.modular.cpp
Go to the documentation of this file.
1 /** @file
2  *
3  * @ingroup implementationMaxExternals
4  *
5  * @brief j.modular - external to manage local and distant application
6  *
7  * @details
8  *
9  * @authors Théo de la Hogue, Trond Lossius
10  *
11  * @copyright Copyright © 2010 Théo de la Hogue @n
12  * This code is licensed under the terms of the "New BSD License" @n
13  * http://creativecommons.org/licenses/BSD/
14  */
15 
16 
18 
19 #define dump_out 0
20 
21 // This is used to store extra data
22 typedef struct extra {
23 
24  TTSymbol protocolName; // remember the handled protocol
25 
26 } t_extra;
27 #define EXTRA ((t_extra*)x->extra)
28 
29 
30 // Definitions
31 void WrapTTApplicationClass(WrappedClassPtr c);
32 void WrappedApplicationClass_new(TTPtr self, long argc, t_atom *argv);
33 void WrappedApplicationClass_free(TTPtr self);
34 
35 void modular_assist(TTPtr self, void *b, long msg, long arg, char *dst);
36 
37 void modular_protocol_setup(TTPtr self, t_symbol *msg, long argc, t_atom *argv);
38 void modular_protocol_scan(TTPtr self, t_symbol *msg, long argc, t_atom *argv);
39 
40 void modular_namespace_read(TTPtr self, t_symbol *msg, long argc, t_atom *argv);
41 void modular_namespace_doread(TTPtr self, t_symbol *msg, long argc, t_atom *argv);
42 
43 void modular_namespace_write(TTPtr self, t_symbol *msg, long argc, t_atom *argv);
44 void modular_namespace_dowrite(TTPtr self, t_symbol *msg, long argc, t_atom *argv);
45 
46 int C74_EXPORT main(void)
47 {
48  ModularSpec *spec = new ModularSpec;
49  spec->_wrap = &WrapTTApplicationClass;
50  spec->_new = &WrappedApplicationClass_new;
51  spec->_any = NULL;
52  spec->_free = &WrappedApplicationClass_free;
53 
54  return wrapTTModularClassAsMaxClass(kTTSym_Application, "j.modular", NULL, spec);
55 }
56 
57 void WrapTTApplicationClass(WrappedClassPtr c)
58 {
59  class_addmethod(c->maxClass, (method)modular_assist, "assist", A_CANT, 0L);
60 
61  class_addmethod(c->maxClass, (method)modular_protocol_setup, "protocol/setup", A_GIMME, 0);
62 
63  class_addmethod(c->maxClass, (method)modular_protocol_scan, "protocol/scan", A_GIMME, 0);
64 
65  class_addmethod(c->maxClass, (method)modular_namespace_read, "namespace/read", A_GIMME, 0);
66 
67  class_addmethod(c->maxClass, (method)modular_namespace_write, "namespace/write", A_GIMME, 0);
68 }
69 
70 void WrappedApplicationClass_new(TTPtr self, long argc, t_atom *argv)
71 {
73  TTSymbol applicationName;
74  TTSymbol protocolName;
75  TTObject protocol, anXmlHandler;
76  TTValue v, args, out;
77  long attrstart = attr_args_offset(argc, argv); // support normal arguments
78 
79  // j.modular can handle the local application (1 argument to declare a protocol to use)
80  if (attrstart <= 1) {
81 
82  // our wrapped object is the local application
84  x->wrappedObject.get("name", applicationName);
85 
86  if (attrstart == 1)
87  protocolName = TTSymbol(atom_getsym(argv)->s_name);
88 
89  }
90  // or it can handle a distant application (2 arguments to declare the name of the distant application and the protocol to use)
91  else if (attrstart == 2) {
92 
93  // our wrapped object is a distant application
94  applicationName = TTSymbol(atom_getsym(argv)->s_name);
95  x->wrappedObject = accessApplication(applicationName);
96 
97  // if the application doesn't exists
98  if (!x->wrappedObject.valid()) {
99 
100  // create the application
101  TTModularApplicationManager->sendMessage("ApplicationInstantiateDistant", applicationName, out);
102  x->wrappedObject = out[0];
103  }
104 
105  protocolName = TTSymbol(atom_getsym(argv+1)->s_name);
106 
107  // set the type of the application depending on the plugin
108  if (protocolName == TTSymbol("Minuit"))
109  x->wrappedObject.set(kTTSym_type, TTSymbol("mirror"));
110  else
111  x->wrappedObject.set(kTTSym_type, TTSymbol("proxy"));
112  }
113 
114  // j.modular handle only one protocol per application
115  if (protocolName != kTTSymEmpty) {
116 
117  protocol = accessProtocol(protocolName);
118 
119  // check if the protocol has been loaded
120  if (!protocol.valid()) {
121 
122  if (TTModularApplicationManager->sendMessage("ProtocolInstantiate", protocolName, out))
123  object_error((t_object*)x, "the %s protocol is not available", protocolName.c_str());
124 
125  protocol = out[0];
126  }
127 
128  // register the application to the protocol
129  protocol.send("ApplicationRegister", applicationName, out);
130 
131  // run this protocol
132  protocol.send("Run");
133  }
134 
135  // Prepare extra data
136  x->extra = (t_extra*)malloc(sizeof(t_extra));
137  EXTRA->protocolName = protocolName;
138 
139  // create internal TTXmlHandler
140  anXmlHandler = TTObject(kTTSym_XmlHandler);
141  x->internals->append(kTTSym_XmlHandler, anXmlHandler);
142  anXmlHandler.set(kTTSym_object, x->wrappedObject);
143 
144  if (attrstart && argv) attr_args_process(x, argc, argv);
145 }
146 
147 void WrappedApplicationClass_free(TTPtr self)
148 {
150  TTObject localApplication = accessApplicationLocal;
151  TTObject protocol;
152  TTSymbol applicationName;
153 
154  // get application name
155  x->wrappedObject.get(kTTSym_name, applicationName);
156 
157  // the xmlhandler have to forget the application object
158  TTValue o;
159  x->internals->lookup(kTTSym_XmlHandler, o);
160  TTObject empty, anXmlHandler = o[0];
161  anXmlHandler.set(kTTSym_object, empty);
162 
163  // unregister the application to the protocol
164  if (EXTRA->protocolName != kTTSymEmpty) {
165 
166  TTValue out;
167  protocol = accessProtocol(EXTRA->protocolName);
168  protocol.send("ApplicationUnregister", applicationName, out);
169  }
170 
171  // don't release the local application
172  if (!(x->wrappedObject == localApplication)) {
173 
174  TTValue out;
175  x->wrappedObject = TTObject();
176  TTModularApplicationManager->sendMessage("ApplicationRelease", applicationName, out);
177  }
178 
179  free(EXTRA);
180 }
181 
182 // Method for Assistance Messages
183 void modular_assist(TTPtr self, void *b, long msg, long arg, char *dst)
184 {
185  if (msg==1) // Inlet
186  strcpy(dst, "input");
187  else { // Outlets
188  switch(arg) {
189  case dump_out:
190  strcpy(dst, "dumpout");
191  break;
192  }
193  }
194 }
195 
196 void modular_protocol_setup(TTPtr self, t_symbol *msg, long argc, t_atom *argv)
197 {
199  TTSymbol applicationName, parameterName;
200  TTObject aProtocol;
201  TTValue v, out, parameterValue;
202  long ac;
203  t_atom *av;
204 
205  // get the protocol object
206  aProtocol = accessProtocol(EXTRA->protocolName);
207  if (aProtocol.valid()) {
208 
209  if (x->wrappedObject.valid()) {
210 
211  if (argc && argv) {
212 
213  // stop protocol
214  aProtocol.send("Stop");
215 
216  // select this application
217  x->wrappedObject.get(kTTSym_name, applicationName);
218  if (aProtocol.send("ApplicationSelect", applicationName, out))
219  object_error((t_object*)x, "%s is not registered to the %s protocol", applicationName.c_str(), EXTRA->protocolName.c_str());
220 
221  // set parameters
222  parameterName = TTSymbol(atom_getsym(argv)->s_name);
223  jamoma_ttvalue_from_Atom(parameterValue, _sym_nothing, argc-1, argv+1);
224  if (aProtocol.set(parameterName, parameterValue))
225  object_error((t_object*)x, "%s is not a parameter of %s protocol", parameterName.c_str(), EXTRA->protocolName.c_str());
226 
227  // run protocol
228  aProtocol.send("Run");
229  }
230  // or if no arg : dumpout the current setup
231  else {
232 
233  // select this application
234  x->wrappedObject.get(kTTSym_name, applicationName);
235  if (aProtocol.send("ApplicationSelect", applicationName, out))
236  object_error((t_object*)x, "%s is not registered to the %s protocol", applicationName.c_str(), EXTRA->protocolName.c_str());
237 
238  aProtocol.get("parameterNames", out);
239  for (TTElementIter it = out.begin() ; it != out.end() ; it++) {
240 
241  TTSymbol name = TTElement(*it);
242  aProtocol.get(parameterName, parameterValue);
243  parameterValue.prepend(name);
244  ac = 0;
245  av = NULL;
246  jamoma_ttvalue_to_Atom(parameterValue, &ac, &av);
247  object_obex_dumpout(self, gensym("protocol/setup"), ac, av);
248  }
249  }
250  }
251  else
252  object_error((t_object*)x, "doesn't handle any application");
253  }
254 }
255 
256 void modular_protocol_scan(TTPtr self, t_symbol *msg, long argc, t_atom *argv)
257 {
259  TTObject aProtocol;
260  TTValue args, out;
261  long ac = 0;
262  t_atom *av = NULL;
263 
264  // get the protocol object
265  aProtocol = accessProtocol(EXTRA->protocolName);
266  if (aProtocol.valid()) {
267 
268  jamoma_ttvalue_from_Atom(args, _sym_nothing, argc, argv);
269 
270  aProtocol.send("Scan", args, out);
271 
272  // add "inputs" or "outputs" symbol before
273  out.prepend(args);
274 
275  jamoma_ttvalue_to_Atom(out, &ac, &av);
276  object_obex_dumpout(self, gensym("protocol/scan"), ac, av);
277  }
278 }
279 
280 void modular_namespace_read(TTPtr self, t_symbol *msg, long argc, t_atom *argv)
281 {
282  defer(self, (method)modular_namespace_doread, msg, argc, argv);
283 }
284 
285 void modular_namespace_doread(TTPtr self, t_symbol *msg, long argc, t_atom *argv)
286 {
288  TTValue o, v, none;
289  TTSymbol fullpath;
290  TTObject anXmlHandler;
291  TTErr tterr;
292 
293  if (x->wrappedObject.valid()) {
294 
295  fullpath = jamoma_file_read((t_object*)x, argc, argv, (t_fourcc)'TEXT');
296  v.append(fullpath);
297 
298  tterr = x->internals->lookup(kTTSym_XmlHandler, o);
299 
300  if (!tterr) {
301 
302  anXmlHandler = o[0];
303 
304  critical_enter(0);
305  tterr = anXmlHandler.send(kTTSym_Read, v, none);
306  critical_exit(0);
307 
308  if (!tterr)
309  object_obex_dumpout(self, _sym_read, argc, argv);
310  else
311  object_obex_dumpout(self, _sym_error, 0, NULL);
312  }
313  }
314 }
315 
316 void modular_namespace_write(TTPtr self, t_symbol *msg, long argc, t_atom *argv)
317 {
318  defer(self, (method)modular_namespace_dowrite, msg, argc, argv);
319 }
320 
321 void modular_namespace_dowrite(TTPtr self, t_symbol *msg, long argc, t_atom *argv)
322 {
324  char filename[MAX_FILENAME_CHARS];
325  TTSymbol fullpath;
326  TTValue o, v, none;
327  TTObject anXmlHandler;
328  TTErr tterr;
329 
330  if (x->wrappedObject.valid()) {
331 
332  // Default XML File Name
333  snprintf(filename, MAX_FILENAME_CHARS, "namespace.xml");
334  fullpath = jamoma_file_write((t_object*)x, argc, argv, filename);
335  v.append(fullpath);
336 
337  tterr = x->internals->lookup(kTTSym_XmlHandler, o);
338 
339  if (!tterr) {
340  anXmlHandler = o[0];
341 
342  critical_enter(0);
343  tterr = anXmlHandler.send(kTTSym_Write, v, none);
344  critical_exit(0);
345 
346  if (!tterr)
347  object_obex_dumpout(self, _sym_write, argc, argv);
348  else
349  object_obex_dumpout(self, _sym_error, 0, NULL);
350  }
351  }
352 }
TTErr sendMessage(const TTSymbol name)
TODO: Document this function.
TTErr send(const TTSymbol aName)
Send a message to this object with no arguments.
Definition: TTObject.cpp:135
TTErr wrapTTModularClassAsMaxClass(TTSymbol &ttblueClassName, const char *maxClassName, WrappedClassPtr *c, ModularSpec *specificities)
Wrap a Jamoma class as a Max class.
TTErr lookup(const TTSymbol key, TTValue &value)
Find the value for the given key.
Definition: TTHash.cpp:76
Create and use Jamoma object instances.
Definition: TTObject.h:29
Data structure for storing extra data.
void * extra
used to keep very specific things
TTSymbol JAMOMA_EXPORT jamoma_file_read(t_object *x, long argc, const t_atom *argv, t_fourcc filetype)
Get BOOT style filepath from args or, if no args open a dialog to read a file.
TTHashPtr internals
An hash table to store any internal TTObjectBases (like TTData, TTViewer, ...)
void prepend(const TTValue &aValueToPrepend)
Insert another TTValue before the first element.
Definition: TTValue.h:162
void append(const T &anElementValueToAppend)
Insert a single TTElement at the end.
Definition: TTValue.h:243
void * TTPtr
A generic pointer.
Definition: TTBase.h:248
TTErr get(const TTSymbol aName, T &aReturnedValue) const
Get an attribute value for an object.
TTMODULAR_EXPORT TTApplicationManagerPtr TTModularApplicationManager
Export a pointer to a TTApplicationManager instance.
Definition: TTModular.cpp:34
void JAMOMA_EXPORT jamoma_ttvalue_to_Atom(const TTValue &v, long *argc, t_atom **argv)
Make an Atom array from a TTValue.
TTErr set(const TTSymbol aName, T aValue)
Set an attribute value for an object.
The TTSymbol class is used to represent a string and efficiently pass and compare that string...
Definition: TTSymbol.h:26
TTSymbol JAMOMA_EXPORT jamoma_file_write(t_object *x, long argc, const t_atom *argv, char *default_filename)
Get BOOT style filepath from args or, if no args open a dialog to write a file.
#define accessApplication(applicationName)
Access to an application by name.
TTErr append(const TTSymbol key, const TTValue &value)
Insert an item into the hash table.
Definition: TTHash.cpp:70
#define accessApplicationLocal
Access to local application.
TTObject wrappedObject
The instance of the Jamoma object we are wrapping.
Individual items found in a TTValue.
Definition: TTElement.h:89
const char * c_str() const
Return a pointer to the internal string as a C-string.
Definition: TTSymbol.h:77
void JAMOMA_EXPORT jamoma_ttvalue_from_Atom(TTValue &v, t_symbol *msg, long argc, const t_atom *argv)
Make a TTValue from Atom array.
int C74_EXPORT main(void)
Set up this class as a Max external the first time an object of this kind is instantiated.
Data Structure for this object.
TTErr
Jamoma Error Codes Enumeration of error codes that might be returned by any of the TTBlue functions a...
Definition: TTBase.h:342
Wraps Jamoma Core classes as objects for Max/MSP.
TTBoolean valid() const
Determine if the object contained by this TTObject is truly ready for use.
Definition: TTObject.cpp:179
WrappedModularInstance * WrappedModularInstancePtr
Pointer to a wrapped instance of our object.
#define accessProtocol(protocolName)
Access to a protocol by name.
[doxygenAppendixC_copyExample]
Definition: TTValue.h:34