Jamoma API  0.6.0.a19
Max/source/j.score/j.score.cpp
Go to the documentation of this file.
1 /** @file
2  *
3  * @ingroup implementationMaxExternals
4  *
5  * @brief j.score - external to handle a score project localy or remotely
6  *
7  * @details
8  *
9  * @author Théo de la Hogue
10  *
11  * @copyright Copyright © 2014, Théo de la Hogue @n
12  * This code is licensed under the terms of the "CeCILL-C" @n
13  * http://www.cecill.info
14  */
15 
16 
18 #include "TTScore.h"
19 
20 #define dump_out 0
21 
22 // This is used to store extra data
23 typedef struct extra
24 {
25  TTObject *applicationManager; // TTModularApplicationManager object
26  TTObject *eventStatusCallback; // a callback to report event status
27  TTObject *processStartedCallback; // a callback to report event status
28  TTObject *processEndedCallback; // a callback to report event status
29  TTObject *xmlHandler; // read/write .score file format
30  TTObject *textHandler; // read/write from/to text editor
31  TTString *text; // the text of the editor to read after edclose
32  t_object* textEditor; // the text editor window
33  TTPtr filewatcher; // a .score filewatcher
34 } t_extra;
35 #define EXTRA ((t_extra*)x->extra)
36 
37 
38 /** Set up what methods (Max messages) that the wrapped class is to respond to.
39  @param c Pointer to the wrapped class.
40  */
41 void WrapTTScoreClass(WrappedClassPtr c);
42 
43 /** Constructor: Initiate the wrapped object instance.
44  @param self Pointer to the object.
45  @param argc The number of arguments to the new object instance
46  @param argv Pointer to the array of atoms containing the arguments to the object instance.
47  */
48 void WrappedScoreClass_new(TTPtr self, long argc, t_atom *argv);
49 
50 /** Deconstructor: Destroy the object and free memory assigned to it.
51  @param self Pointer to the object.
52  */
53 void WrappedScoreClass_free(TTPtr self);
54 
55 /** Display assist messages for inlets and outlets in Max.
56  @param self Pointer to the object.
57  @param b This does not seem to be used.
58  @param msg "1" if we are to display assist message for an inlet, else we are to display assist message for an outlet.
59  @param arg The number of the inlet or outlet that we are to display assist message for. 0 is the leftmost.
60  @param dst Pointer to the destination used for displaying the assist message.
61  */
62 void score_assist(TTPtr self, void *b, long msg, long arg, char *dst);
63 
64 /**
65  @param self
66  @param filename
67  @param path
68  */
69 void score_filechanged(TTPtr self, char *filename, short path);
70 
71 /**
72  @param self
73  @param msg
74  @param argc
75  @param argv
76  */
77 void score_read(TTPtr self, t_symbol *msg, long argc, t_atom *argv);
78 
79 /**
80  @param self
81  @param msg
82  @param argc
83  @param argv
84  */
85 void score_doread(TTPtr self, t_symbol *msg, long argc, t_atom *argv);
86 
87 /**
88  @param self
89  */
90 void score_read_again(TTPtr self);
91 
92 /**
93  @param self
94  */
95 void score_doread_again(TTPtr self);
96 
97 /**
98  @param self
99  @param msg
100  @param argc
101  @param argv
102  */
103 void score_write(TTPtr self, t_symbol *msg, long argc, t_atom *argv);
104 
105 /**
106  @param self
107  @param msg
108  @param argc
109  @param argv
110  */
111 void score_dowrite(TTPtr self, t_symbol *msg, long argc, t_atom *argv);
112 
113 /**
114  @param self
115  */
116 void score_write_again(TTPtr self);
117 
118 /**
119  @param self
120  */
121 void score_dowrite_again(TTPtr self);
122 
123 /**
124  @param self
125  @param msg
126  @param argc
127  @param argv
128  */
129 void score_edit(TTPtr self, t_symbol *msg, long argc, const t_atom *argv);
130 
131 /**
132  @param self
133  @param text
134  @param size
135  */
136 void score_edclose(TTPtr self, char **text, long size);
137 
138 /**
139  @param self
140  */
141 void score_doedit(TTPtr self);
142 
143 
144 void score_eventStatusCallback(const TTValue& baton, const TTValue& value);
145 void score_processStartedCallback(const TTValue& baton, const TTValue& value);
146 void score_processEndedCallback(const TTValue& baton, const TTValue& value);
147 
148 void score_doreport(TTPtr self, t_symbol *msg, long argc, t_atom *argv);
149 
150 int C74_EXPORT main(void)
151 {
152  ModularSpec *spec = new ModularSpec;
153  spec->_wrap = &WrapTTScoreClass;
154  spec->_new = &WrappedScoreClass_new;
155  spec->_any = NULL;
156  spec->_free = &WrappedScoreClass_free;
157 
158  // wrap Scenario class
159  TTSymbol kTTSym_Scenario = TTSymbol("Scenario");
160  return wrapTTModularClassAsMaxClass(kTTSym_Scenario, "j.score", NULL, spec);
161 }
162 
163 void WrapTTScoreClass(WrappedClassPtr c)
164 {
165  class_addmethod(c->maxClass, (method)score_assist, "assist", A_CANT, 0L);
166  class_addmethod(c->maxClass, (method)score_filechanged, "filechanged", A_CANT, 0);
167 
168  class_addmethod(c->maxClass, (method)score_read, "read", A_GIMME, 0);
169  class_addmethod(c->maxClass, (method)score_write, "write", A_GIMME, 0);
170  class_addmethod(c->maxClass, (method)score_edit, "edit", A_GIMME, 0);
171 
172  class_addmethod(c->maxClass, (method)score_read_again, "read/again", 0);
173  class_addmethod(c->maxClass, (method)score_write_again, "write/again", 0);
174 }
175 
176 void WrappedScoreClass_new(TTPtr self, long argc, t_atom *argv)
177 {
179  long attrstart = attr_args_offset(argc, argv); // support normal arguments
180 
181  // j.score
182  if (attrstart)
183  {
184  ;
185  }
186 
187  // create main scenario
188  x->wrappedObject = TTObject("Scenario");
189 
190  // prepare extra data
191  x->extra = (t_extra*)malloc(sizeof(t_extra));
192  EXTRA->applicationManager = new TTObject(TTModularApplicationManager);
193 
194  EXTRA->eventStatusCallback = new TTObject("callback");
195  EXTRA->eventStatusCallback->set("baton", TTPtr(self));
196  EXTRA->eventStatusCallback->set("function", TTPtr(&score_eventStatusCallback));
197  EXTRA->eventStatusCallback->set("notification", TTSymbol("EventStatusChanged"));
198 
199  EXTRA->processStartedCallback = new TTObject("callback");
200  EXTRA->processStartedCallback->set("baton", TTPtr(self));
201  EXTRA->processStartedCallback->set("function", TTPtr(&score_processEndedCallback));
202  EXTRA->processStartedCallback->set("notification", TTSymbol("ProcessEnded"));
203 
204  EXTRA->processEndedCallback = new TTObject("callback");
205  EXTRA->processEndedCallback->set("baton", TTPtr(self));
206  EXTRA->processEndedCallback->set("function", TTPtr(&score_processStartedCallback));
207  EXTRA->processEndedCallback->set("notification", TTSymbol("ProcessStarted"));
208 
209  EXTRA->xmlHandler = new TTObject(kTTSym_XmlHandler);
210  EXTRA->textHandler = new TTObject(kTTSym_TextHandler);
211  EXTRA->text = NULL;
212  EXTRA->textEditor = NULL;
213  EXTRA->filewatcher = NULL;
214 
215  // fill application manager and scenario
216  EXTRA->xmlHandler->set(kTTSym_object, TTValue(EXTRA->applicationManager, x->wrappedObject));
217 
218  // read attributes
219  if (attrstart && argv)
220  attr_args_process(x, argc, argv);
221 }
222 
224 {
226 
227  // stop the score
228  x->wrappedObject.send("End");
229 
230  // delete filewatcher
231  if (EXTRA->filewatcher)
232  {
233  filewatcher_stop(EXTRA->filewatcher);
234  object_free(EXTRA->filewatcher);
235  }
236 
237  free(EXTRA);
238 }
239 
240 // Method for Assistance Messages
241 void score_assist(TTPtr self, void *b, long msg, long arg, char *dst)
242 {
243  if (msg==1) // Inlet
244  strcpy(dst, "input");
245  else { // Outlets
246  switch(arg)
247  {
248  case dump_out:
249  strcpy(dst, "dumpout");
250  break;
251  }
252  }
253 }
254 
255 void score_filechanged(TTPtr self, char *filename, short path)
256 {
257  t_atom a;
258  atom_setsym(&a, gensym(filename));
259  defer_low(self, (method)score_doread, gensym("read"), 1, &a);
260 }
261 
262 void score_read(TTPtr self, t_symbol *msg, long argc, t_atom *argv)
263 {
264  defer(self, (method)score_doread, msg, argc, argv);
265 }
266 
267 void score_doread(TTPtr self, t_symbol *msg, long argc, t_atom *argv)
268 {
270 
271  if (x->wrappedObject.valid())
272  {
273  // stop the score
274  x->wrappedObject.send("End");
275 
276  TTSymbol userpath = jamoma_file_read((t_object*)x, argc, argv, 0);
277 
278  critical_enter(0);
279  TTErr err = EXTRA->xmlHandler->send(kTTSym_Read, userpath);
280  critical_exit(0);
281 
282  if (!err)
283  object_obex_dumpout(self, _sym_read, argc, argv);
284  else
285  object_obex_dumpout(self, _sym_error, 0, NULL);
286 
287  // replace filewatcher
288  if (EXTRA->filewatcher)
289  {
290  filewatcher_stop(EXTRA->filewatcher);
291  object_free(EXTRA->filewatcher);
292  }
293 
294  short outvol;
295  t_fourcc outtype, filetype = 'TEXT';
296  char filepath[MAX_FILENAME_CHARS];
297 
298  strncpy_zero(filepath, userpath.c_str(), MAX_FILENAME_CHARS); // must copy symbol before calling locatefile_extended
299  if (locatefile_extended((char*)filepath, &outvol, &outtype, &filetype, 0))
300  return;
301 
302  EXTRA->filewatcher = filewatcher_new((t_object*)x, outvol, (char*)filepath);
303  filewatcher_start(EXTRA->filewatcher);
304 
305  // prepare report machnism
306  TTValue objects;
307 
308  // for all time events
309  x->wrappedObject.get("timeEvents", objects);
310  for (TTUInt32 i = 0 ; i < objects.size() ; i++)
311  {
312  // observe the "EventReadyChanged" notification
313  TTObject timeEvent = objects[i];
314  timeEvent.registerObserverForNotifications(*EXTRA->eventStatusCallback);
315  }
316 
317  // for all time processes
318  x->wrappedObject.get("timeProcesses", objects);
319  for (TTUInt32 i = 0 ; i < objects.size() ; i++)
320  {
321  // observe the "processStarted" and processEnded notification
322  TTObject timeProcess = objects[i];
323  timeProcess.registerObserverForNotifications(*EXTRA->processStartedCallback);
324  timeProcess.registerObserverForNotifications(*EXTRA->processEndedCallback);
325  }
326 
327  // for the main scenario
328  x->wrappedObject.registerObserverForNotifications(*EXTRA->processStartedCallback);
329  x->wrappedObject.registerObserverForNotifications(*EXTRA->processEndedCallback);
330  }
331 }
332 
334 {
335  defer(self, (method)score_doread_again, NULL, 0, NULL);
336 }
337 
339 {
341 
342  if (x->wrappedObject.valid())
343  {
344  // stop the score
345  x->wrappedObject.send("End");
346 
347  critical_enter(0);
348  TTErr err = EXTRA->xmlHandler->send(kTTSym_ReadAgain);
349  critical_exit(0);
350 
351  if (!err)
352  object_obex_dumpout(self, _sym_read, 0, NULL);
353  else
354  object_obex_dumpout(self, _sym_error, 0, NULL);
355  }
356 }
357 
358 void score_write(TTPtr self, t_symbol *msg, long argc, t_atom *argv)
359 {
360  defer(self, (method)score_dowrite, msg, argc, argv);
361 }
362 
363 void score_dowrite(TTPtr self, t_symbol *msg, long argc, t_atom *argv)
364 {
366 
367  if (x->wrappedObject.valid())
368  {
369  // stop filewatcher
370  if (EXTRA->filewatcher)
371  filewatcher_stop(EXTRA->filewatcher);
372 
373  // default xml file name
374  char filename[MAX_FILENAME_CHARS];
375  snprintf(filename, MAX_FILENAME_CHARS, "untitled.score");
376 
377  TTSymbol userpath = jamoma_file_write((t_object*)x, argc, argv, filename);
378 
379  critical_enter(0);
380  TTErr err = EXTRA->xmlHandler->send(kTTSym_Write, userpath);
381  critical_exit(0);
382 
383  if (!err)
384  object_obex_dumpout(self, _sym_write, argc, argv);
385  else
386  object_obex_dumpout(self, _sym_error, 0, NULL);
387 
388  // replace filewatcher
389  if (EXTRA->filewatcher)
390  {
391  filewatcher_stop(EXTRA->filewatcher);
392  object_free(EXTRA->filewatcher);
393  }
394 
395  short outvol;
396  t_fourcc outtype, filetype = 'TEXT';
397  char filepath[MAX_FILENAME_CHARS];
398 
399  strncpy_zero(filepath, userpath.c_str(), MAX_FILENAME_CHARS); // must copy symbol before calling locatefile_extended
400  if (locatefile_extended((char*)filepath, &outvol, &outtype, &filetype, 0))
401  return;
402 
403  EXTRA->filewatcher = filewatcher_new((t_object*)x, outvol, (char*)filepath);
404  filewatcher_start(EXTRA->filewatcher);
405  }
406 }
407 
409 {
410  defer(self, (method)score_dowrite_again, NULL, 0, NULL);
411 }
412 
414 {
416 
417  if (x->wrappedObject.valid())
418  {
419  // stop filewatcher
420  if (EXTRA->filewatcher)
421  filewatcher_stop(EXTRA->filewatcher);
422 
423  critical_enter(0);
424  TTErr err = EXTRA->xmlHandler->send(kTTSym_WriteAgain);
425  critical_exit(0);
426 
427  if (!err)
428  object_obex_dumpout(self, _sym_write, 0, NULL);
429  else
430  object_obex_dumpout(self, _sym_error, 0, NULL);
431 
432  // start filewatcher
433  if (EXTRA->filewatcher)
434  filewatcher_start(EXTRA->filewatcher);
435  }
436 }
437 
438 void score_edit(TTPtr self, t_symbol *msg, long argc, const t_atom *argv)
439 {
441  TTString *buffer;
442  char title[MAX_FILENAME_CHARS];
443  t_atom a;
444 
445  // find event's state to edit it in text format
446  if (argc && argv)
447  {
448  if (atom_gettype(argv) == A_SYM)
449  {
450  TTBoolean found = NO;
451 
452  // get all scenario events
453  TTValue events;
454  x->wrappedObject.get("timeEvents", events);
455 
456  for (TTElementIter it = events.begin(); it != events.end(); it++)
457  {
458  TTObject event = TTElement(*it);
459  TTSymbol name;
460  event.get("name", name);
461 
462  if (name == TTSymbol(atom_getsym(argv)->s_name))
463  {
464  TTObject state;
465  event.get("state", state);
466  EXTRA->textHandler->set(kTTSym_object, state);
467  found = YES;
468  }
469  }
470 
471  if (!found)
472  {
473  object_error((t_object*)x, "%s event does'nt exist", atom_getsym(argv)->s_name);
474  return;
475  }
476  }
477  }
478 
479  // only one editor can be open in the same time
480  if (!EXTRA->textEditor)
481  {
482  EXTRA->textEditor = (t_object*)object_new(_sym_nobox, _sym_jed, x, 0);
483 
484  // write state content into a string buffer
485  buffer = new TTString();
486 
487  critical_enter(0);
488  TTErr err = EXTRA->textHandler->send(kTTSym_Write, (TTPtr)buffer);
489  critical_exit(0);
490 
491  // pass the string buffer to the editor
492  object_method(EXTRA->textEditor, _sym_settext, buffer->c_str(), _sym_utf_8);
493  object_attr_setchar(EXTRA->textEditor, gensym("scratch"), 1);
494 
495  snprintf(title, MAX_FILENAME_CHARS, "state editor");
496  object_attr_setsym(EXTRA->textEditor, _sym_title, gensym(title));
497 
498  if (err)
499  {
500  // output error
501  object_obex_dumpout(self, _sym_error, 0, NULL);
502  }
503  else
504  {
505  // output a flag
506  atom_setsym(&a, gensym("opened"));
507  object_obex_dumpout(self, gensym("editor"), 1, &a);
508  }
509 
510  buffer->clear();
511  delete buffer;
512  buffer = NULL;
513  }
514 }
515 
516 void score_edclose(TTPtr self, char **text, long size)
517 {
519 
520  EXTRA->text = new TTString(*text);
521  EXTRA->textEditor = NULL;
522 
523  defer_low((t_object*)x, (method)score_doedit, NULL, 0, NULL);
524 }
525 
526 void score_doedit(TTPtr self)
527 {
529  t_atom a;
530 
531  // get the string buffer
532  critical_enter(0);
533  TTErr err = EXTRA->textHandler->send(kTTSym_Read, (TTPtr)EXTRA->text);
534  critical_exit(0);
535 
536  if (err)
537  {
538  // output error
539  object_obex_dumpout(self, _sym_error, 0, NULL);
540  }
541  else
542  {
543  // output a flag
544  atom_setsym(&a, gensym("closed"));
545  object_obex_dumpout(self, gensym("editor"), 1, &a);
546  }
547 
548  delete EXTRA->text;
549  EXTRA->text = NULL;
550  EXTRA->textEditor = NULL;
551 }
552 
553 void score_eventStatusCallback(const TTValue& baton, const TTValue& value)
554 {
555  TTObject event;
556  TTValue v;
557  TTSymbol name, status;
558  t_atom report[2];
559 
560  // unpack baton (self)
562 
563  // Unpack data (event)
564  event = value[0];
565 
566  // get name
567  event.get("name", v);
568  name = v[0];
569 
570  // get status
571  event.get("status", v);
572  status = v[0];
573 
574  // return a simple status symbol
575  if (status == kTTSym_eventWaiting) status = TTSymbol("waiting");
576  else if (status == kTTSym_eventPending) status = TTSymbol("pending");
577  else if (status == kTTSym_eventHappened) status = TTSymbol("happened");
578  else if (status == kTTSym_eventDisposed) status = TTSymbol("disposed");
579 
580  // prepare report for event status : <name status>
581  atom_setsym(report, gensym((char*)name.c_str()));
582  atom_setsym(report+1, gensym((char*)status.c_str()));
583  defer_low((t_object*)x, (method)score_doreport, gensym("event"), 2, report);
584 }
585 
586 void score_processStartedCallback(const TTValue& baton, const TTValue& value)
587 {
588  TTObject process;
589  TTValue v;
590  TTSymbol name;
591  t_atom report[2];
592 
593  // unpack baton (self)
595 
596  // Unpack data (process)
597  process = value[0];
598 
599  // get name
600  process.get("name", v);
601  name = v[0];
602 
603  // prepare report for event status : <name status>
604  atom_setsym(report, gensym((char*)name.c_str()));
605  atom_setsym(report+1, gensym("started"));
606  defer_low((t_object*)x, (method)score_doreport, gensym("process"), 2, report);
607 }
608 
609 void score_processEndedCallback(const TTValue& baton, const TTValue& value)
610 {
611  TTObject process;
612  TTValue v;
613  TTSymbol name;
614  t_atom report[2];
615 
616  // unpack baton (self)
618 
619  // Unpack data (process)
620  process = value[0];
621 
622  // get name
623  process.get("name", v);
624  name = v[0];
625 
626  // prepare report for event status : <name status>
627  atom_setsym(report, gensym((char*)name.c_str()));
628  atom_setsym(report+1, gensym("ended"));
629  defer_low((t_object*)x, (method)score_doreport, gensym("process"), 2, report);
630 }
631 
632 void score_doreport(TTPtr self, t_symbol *msg, long argc, t_atom *argv)
633 {
634  object_obex_dumpout(self, msg, argc, argv);
635 }
636 
void score_filechanged(TTPtr self, char *filename, short path)
bool TTBoolean
Boolean flag, same as Boolean on the Mac.
Definition: TTBase.h:167
void score_assist(TTPtr self, void *b, long msg, long arg, char *dst)
Display assist messages for inlets and outlets in Max.
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.
void WrappedScoreClass_new(TTPtr self, long argc, t_atom *argv)
Constructor: Initiate the wrapped object instance.
void WrapTTScoreClass(WrappedClassPtr c)
Set up what methods (Max messages) that the wrapped class is to respond to.
void score_edit(TTPtr self, t_symbol *msg, long argc, const t_atom *argv)
void score_dowrite_again(TTPtr self)
Create and use Jamoma object instances.
Definition: TTObject.h:29
size_type size() const noexcept
Return the number of elements.
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.
void score_write(TTPtr self, t_symbol *msg, long argc, t_atom *argv)
void score_doread_again(TTPtr self)
void WrappedScoreClass_free(TTPtr self)
Deconstructor: Destroy the object and free memory assigned to it.
void * TTPtr
A generic pointer.
Definition: TTBase.h:248
TTErr get(const TTSymbol aName, T &aReturnedValue) const
Get an attribute value for an object.
void score_write_again(TTPtr self)
TTMODULAR_EXPORT TTApplicationManagerPtr TTModularApplicationManager
Export a pointer to a TTApplicationManager instance.
Definition: TTModular.cpp:34
TTErr registerObserverForNotifications(const TTObject &anObservingObject)
Register an observer.
Definition: TTObject.cpp:155
void score_dowrite(TTPtr self, t_symbol *msg, long argc, t_atom *argv)
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.
void get(const TTUInt16 index, T &returnedElementValue) const
DEPRECATED.
Definition: TTValue.h:591
TTObject wrappedObject
The instance of the Jamoma object we are wrapping.
Individual items found in a TTValue.
Definition: TTElement.h:89
int C74_EXPORT main(void)
Set up this class as a Max external the first time an object of this kind is instantiated.
const char * c_str() const
Return a pointer to the internal string as a C-string.
Definition: TTSymbol.h:77
void score_doedit(TTPtr self)
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.
std::uint32_t TTUInt32
32 bit unsigned integer
Definition: TTBase.h:178
void score_read(TTPtr self, t_symbol *msg, long argc, t_atom *argv)
The TTString class is used to represent a string.
Definition: TTString.h:34
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.
void score_doread(TTPtr self, t_symbol *msg, long argc, t_atom *argv)
[doxygenAppendixC_copyExample]
Definition: TTValue.h:34
void score_read_again(TTPtr self)
void score_edclose(TTPtr self, char **text, long size)