Jamoma API  0.6.0.a19
PureData/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, 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 
151 extern "C" void JAMOMA_EXPORT_MAXOBJ setup_j0x2escore(void)
152 {
153  ModularSpec *spec = new ModularSpec;
154  spec->_wrap = &WrapTTScoreClass;
155  spec->_new = &WrappedScoreClass_new;
156  spec->_any = NULL;
157  spec->_free = &WrappedScoreClass_free;
158 
159  // wrap Scenario class
160  TTSymbol kTTSym_Scenario = TTSymbol("Scenario");
161  return (void) wrapTTModularClassAsPdClass(kTTSym_Scenario, "j.score", NULL, spec);
162 }
163 
164 void WrapTTScoreClass(WrappedClassPtr c)
165 {
166  eclass_addmethod(c->pdClass, (method)score_assist, "assist", A_CANT, 0L);
167  eclass_addmethod(c->pdClass, (method)score_filechanged, "filechanged", A_CANT, 0);
168 
169  eclass_addmethod(c->pdClass, (method)score_read, "read", A_GIMME, 0);
170  eclass_addmethod(c->pdClass, (method)score_write, "write", A_GIMME, 0);
171  eclass_addmethod(c->pdClass, (method)score_edit, "edit", A_GIMME, 0);
172 
173  eclass_addmethod(c->pdClass, (method)score_read_again, "read/again", A_NULL, 0);
174  eclass_addmethod(c->pdClass, (method)score_write_again, "write/again", A_NULL, 0);
175 }
176 
177 void WrappedScoreClass_new(TTPtr self, long argc, t_atom *argv)
178 {
180  long attrstart = attr_args_offset(argc, argv); // support normal arguments
181 
182  // j.score
183  if (attrstart)
184  {
185  ;
186  }
187 
188  // create main scenario
189  x->wrappedObject = TTObject("Scenario");
190 
191  // prepare extra data
192  x->extra = (t_extra*)malloc(sizeof(t_extra));
193  EXTRA->applicationManager = new TTObject(TTModularApplicationManager);
194 
195  EXTRA->eventStatusCallback = new TTObject("callback");
196  EXTRA->eventStatusCallback->set("baton", TTPtr(self));
197  EXTRA->eventStatusCallback->set("function", TTPtr(&score_eventStatusCallback));
198  EXTRA->eventStatusCallback->set("notification", TTSymbol("EventStatusChanged"));
199 
200  EXTRA->processStartedCallback = new TTObject("callback");
201  EXTRA->processStartedCallback->set("baton", TTPtr(self));
202  EXTRA->processStartedCallback->set("function", TTPtr(&score_processEndedCallback));
203  EXTRA->processStartedCallback->set("notification", TTSymbol("ProcessEnded"));
204 
205  EXTRA->processEndedCallback = new TTObject("callback");
206  EXTRA->processEndedCallback->set("baton", TTPtr(self));
207  EXTRA->processEndedCallback->set("function", TTPtr(&score_processStartedCallback));
208  EXTRA->processEndedCallback->set("notification", TTSymbol("ProcessStarted"));
209 
210  EXTRA->xmlHandler = new TTObject(kTTSym_XmlHandler);
211  EXTRA->textHandler = new TTObject(kTTSym_TextHandler);
212  EXTRA->text = NULL;
213  EXTRA->textEditor = NULL;
214  EXTRA->filewatcher = NULL;
215 
216  // fill application manager and scenario
217  EXTRA->xmlHandler->set(kTTSym_object, TTValue(EXTRA->applicationManager, x->wrappedObject));
218 
219  // read attributes
220  if (attrstart && argv)
221  attr_args_process(x, argc, argv);
222 }
223 
225 {
227 
228  // stop the score
229  x->wrappedObject.send("End");
230 
231  // delete filewatcher
232  /*
233  if (EXTRA->filewatcher)
234  {
235  filewatcher_stop(EXTRA->filewatcher);
236  object_free(EXTRA->filewatcher);
237  }
238  */
239 
240  free(EXTRA);
241 }
242 
243 // Method for Assistance Messages
244 void score_assist(TTPtr self, void *b, long msg, long arg, char *dst)
245 {
246  if (msg==1) // Inlet
247  strcpy(dst, "input");
248  else { // Outlets
249  switch(arg)
250  {
251  case dump_out:
252  strcpy(dst, "dumpout");
253  break;
254  }
255  }
256 }
257 
258 void score_filechanged(TTPtr self, char *filename, short path)
259 {
260  t_atom a;
261  atom_setsym(&a, gensym(filename));
262  score_doread(self, gensym("read"),1,&a);
263 }
264 
265 void score_read(TTPtr self, t_symbol *msg, long argc, t_atom *argv)
266 {
267  score_doread(self,msg,argc,argv);
268 }
269 
270 void score_doread(TTPtr self, t_symbol *msg, long argc, t_atom *argv)
271 {
273 
274  if (x->wrappedObject.valid())
275  {
276  // stop the score
277  x->wrappedObject.send("End");
278 
279  TTSymbol userpath = jamoma_file_read((t_object*)x, argc, argv, 0);
280 
281  // critical_enter(0);
282  TTErr err = EXTRA->xmlHandler->send(kTTSym_Read, userpath);
283  // critical_exit(0);
284 
285  if (!err)
286  object_obex_dumpout(self, _sym_read, argc, argv);
287  else
288  object_obex_dumpout(self, _sym_error, 0, NULL);
289 
290  // replace filewatcher
291  /*
292  if (EXTRA->filewatcher)
293  {
294  filewatcher_stop(EXTRA->filewatcher);
295  object_free(EXTRA->filewatcher);
296  }
297  */
298 
299  short outvol;
300  t_fourcc outtype, filetype = 'TEXT';
301  char filepath[MAX_FILENAME_CHARS];
302 
303  strncpy(filepath, userpath.c_str(), MAX_FILENAME_CHARS); // must copy symbol before calling locatefile_extended
304  if (locatefile_extended((char*)filepath, &outvol, &outtype, &filetype, 0))
305  return;
306  /*
307  EXTRA->filewatcher = filewatcher_new((t_object*)x, outvol, (char*)filepath);
308  filewatcher_start(EXTRA->filewatcher);
309  */
310 
311  // prepare report machnism
312  TTValue objects;
313 
314  // for all time events
315  x->wrappedObject.get("timeEvents", objects);
316  for (TTUInt32 i = 0 ; i < objects.size() ; i++)
317  {
318  // observe the "EventReadyChanged" notification
319  TTObject timeEvent = objects[i];
320  timeEvent.registerObserverForNotifications(*EXTRA->eventStatusCallback);
321  }
322 
323  // for all time processes
324  x->wrappedObject.get("timeProcesses", objects);
325  for (TTUInt32 i = 0 ; i < objects.size() ; i++)
326  {
327  // observe the "processStarted" and processEnded notification
328  TTObject timeProcess = objects[i];
329  timeProcess.registerObserverForNotifications(*EXTRA->processStartedCallback);
330  timeProcess.registerObserverForNotifications(*EXTRA->processEndedCallback);
331  }
332 
333  // for the main scenario
334  x->wrappedObject.registerObserverForNotifications(*EXTRA->processStartedCallback);
335  x->wrappedObject.registerObserverForNotifications(*EXTRA->processEndedCallback);
336  }
337 }
338 
340 {
341  score_doread_again(self);
342 }
343 
345 {
347 
348  if (x->wrappedObject.valid())
349  {
350  // stop the score
351  x->wrappedObject.send("End");
352 
353  // critical_enter(0);
354  TTErr err = EXTRA->xmlHandler->send(kTTSym_ReadAgain);
355  // critical_exit(0);
356 
357  if (!err)
358  object_obex_dumpout(self, _sym_read, 0, NULL);
359  else
360  object_obex_dumpout(self, _sym_error, 0, NULL);
361  }
362 }
363 
364 void score_write(TTPtr self, t_symbol *msg, long argc, t_atom *argv)
365 {
366  score_dowrite(self, msg, argc, argv);
367 }
368 
369 void score_dowrite(TTPtr self, t_symbol *msg, long argc, t_atom *argv)
370 {
372 
373  if (x->wrappedObject.valid())
374  {
375  // stop filewatcher
376  /*
377  if (EXTRA->filewatcher)
378  filewatcher_stop(EXTRA->filewatcher);
379  */
380 
381  // default xml file name
382  char filename[MAX_FILENAME_CHARS];
383  snprintf(filename, MAX_FILENAME_CHARS, "untitled.score");
384 
385  TTSymbol userpath = jamoma_file_write((t_object*)x, argc, argv, filename);
386 
387  // critical_enter(0);
388  TTErr err = EXTRA->xmlHandler->send(kTTSym_Write, userpath);
389  // critical_exit(0);
390 
391  if (!err)
392  object_obex_dumpout(self, _sym_write, argc, argv);
393  else
394  object_obex_dumpout(self, _sym_error, 0, NULL);
395 
396  // replace filewatcher
397  /*
398  if (EXTRA->filewatcher)
399  {
400  filewatcher_stop(EXTRA->filewatcher);
401  object_free(EXTRA->filewatcher);
402  }
403  */
404 
405  short outvol;
406  t_fourcc outtype, filetype = 'TEXT';
407  char filepath[MAX_FILENAME_CHARS];
408 
409  strncpy(filepath, userpath.c_str(), MAX_FILENAME_CHARS); // must copy symbol before calling locatefile_extended
410  /*
411  if (locatefile_extended((char*)filepath, &outvol, &outtype, &filetype, 0))
412  return;
413 
414  EXTRA->filewatcher = filewatcher_new((t_object*)x, outvol, (char*)filepath);
415  filewatcher_start(EXTRA->filewatcher);
416  */
417  }
418 }
419 
421 {
422  score_dowrite_again(self);
423 }
424 
426 {
428 
429  if (x->wrappedObject.valid())
430  {
431  // stop filewatcher
432  /*
433  if (EXTRA->filewatcher)
434  filewatcher_stop(EXTRA->filewatcher);
435  */
436 
437  //critical_enter(0);
438  TTErr err = EXTRA->xmlHandler->send(kTTSym_WriteAgain);
439  //critical_exit(0);
440 
441  if (!err)
442  object_obex_dumpout(self, _sym_write, 0, NULL);
443  else
444  object_obex_dumpout(self, _sym_error, 0, NULL);
445 
446  // start filewatcher
447  /*
448  if (EXTRA->filewatcher)
449  filewatcher_start(EXTRA->filewatcher);
450  */
451  }
452 }
453 
454 void score_edit(TTPtr self, t_symbol *msg, long argc, t_atom *argv)
455 {
457  TTString *buffer;
458  char title[MAX_FILENAME_CHARS];
459  t_atom a;
460 
461  // find event's state to edit it in text format
462  if (argc && argv)
463  {
464  if (atom_gettype(argv) == A_SYM)
465  {
466  TTBoolean found = NO;
467 
468  // get all scenario events
469  TTValue events;
470  x->wrappedObject.get("timeEvents", events);
471 
472  for (TTElementIter it = events.begin(); it != events.end(); it++)
473  {
474  TTObject event = TTElement(*it);
475  TTSymbol name;
476  event.get("name", name);
477 
478  if (name == TTSymbol(atom_getsym(argv)->s_name))
479  {
480  TTObject state;
481  event.get("state", state);
482  EXTRA->textHandler->set(kTTSym_object, state);
483  found = YES;
484  }
485  }
486 
487  if (!found)
488  {
489  pd_error((t_object*)x, "%s event does'nt exist", atom_getsym(argv)->s_name);
490  return;
491  }
492  }
493  }
494 
495  // only one editor can be open in the same time
496  /*
497  if (!EXTRA->textEditor)
498  {
499  EXTRA->textEditor = (t_object*)object_new(_sym_nobox, _sym_jed, x, 0);
500 
501  // write state content into a string buffer
502  buffer = new TTString();
503 
504  critical_enter(0);
505  TTErr err = EXTRA->textHandler->send(kTTSym_Write, (TTPtr)buffer);
506  critical_exit(0);
507 
508  // pass the string buffer to the editor
509  object_method(EXTRA->textEditor, _sym_settext, buffer->c_str(), _sym_utf_8);
510  object_attr_setchar(EXTRA->textEditor, gensym("scratch"), 1);
511 
512  snprintf(title, MAX_FILENAME_CHARS, "state editor");
513  object_attr_setsym(EXTRA->textEditor, _sym_title, gensym(title));
514 
515  if (err)
516  {
517  // output error
518  object_obex_dumpout(self, _sym_error, 0, NULL);
519  }
520  else
521  {
522  // output a flag
523  atom_setsym(&a, gensym("opened"));
524  object_obex_dumpout(self, gensym("editor"), 1, &a);
525  }
526 
527  buffer->clear();
528  delete buffer;
529  buffer = NULL;
530  }
531  */
532 }
533 
534 void score_edclose(TTPtr self, char **text, long size)
535 {
537 
538  EXTRA->text = new TTString(*text);
539  EXTRA->textEditor = NULL;
540 
541  score_doedit(self);
542 }
543 
544 void score_doedit(TTPtr self)
545 {
547  t_atom a;
548 
549  // get the string buffer
550  // critical_enter(0);
551  TTErr err = EXTRA->textHandler->send(kTTSym_Read, (TTPtr)EXTRA->text);
552  // critical_exit(0);
553 
554  if (err)
555  {
556  // output error
557  object_obex_dumpout(self, _sym_error, 0, NULL);
558  }
559  else
560  {
561  // output a flag
562  atom_setsym(&a, gensym("closed"));
563  object_obex_dumpout(self, gensym("editor"), 1, &a);
564  }
565 
566  delete EXTRA->text;
567  EXTRA->text = NULL;
568  EXTRA->textEditor = NULL;
569 }
570 
571 void score_eventStatusCallback(const TTValue& baton, const TTValue& value)
572 {
573  TTObject event;
574  TTValue v;
575  TTSymbol name, status;
576  t_atom report[2];
577 
578  // unpack baton (self)
580 
581  // Unpack data (event)
582  event = value[0];
583 
584  // get name
585  event.get("name", v);
586  name = v[0];
587 
588  // get status
589  event.get("status", v);
590  status = v[0];
591 
592  // return a simple status symbol
593  if (status == kTTSym_eventWaiting) status = TTSymbol("waiting");
594  else if (status == kTTSym_eventPending) status = TTSymbol("pending");
595  else if (status == kTTSym_eventHappened) status = TTSymbol("happened");
596  else if (status == kTTSym_eventDisposed) status = TTSymbol("disposed");
597 
598  // prepare report for event status : <name status>
599  atom_setsym(report, gensym((char*)name.c_str()));
600  atom_setsym(report+1, gensym((char*)status.c_str()));
601  score_doreport(x, gensym("event"), 2, report);
602 }
603 
604 void score_processStartedCallback(const TTValue& baton, const TTValue& value)
605 {
606  TTObject process;
607  TTValue v;
608  TTSymbol name;
609  t_atom report[2];
610 
611  // unpack baton (self)
613 
614  // Unpack data (process)
615  process = value[0];
616 
617  // get name
618  process.get("name", v);
619  name = v[0];
620 
621  // prepare report for event status : <name status>
622  atom_setsym(report, gensym((char*)name.c_str()));
623  atom_setsym(report+1, gensym("started"));
624  score_doreport(x, gensym("process"), 2, report);
625 }
626 
627 void score_processEndedCallback(const TTValue& baton, const TTValue& value)
628 {
629  TTObject process;
630  TTValue v;
631  TTSymbol name;
632  t_atom report[2];
633 
634  // unpack baton (self)
636 
637  // Unpack data (process)
638  process = value[0];
639 
640  // get name
641  process.get("name", v);
642  name = v[0];
643 
644  // prepare report for event status : <name status>
645  atom_setsym(report, gensym((char*)name.c_str()));
646  atom_setsym(report+1, gensym("ended"));
647  score_doreport(x, gensym("process"), 2, report);
648 }
649 
650 void score_doreport(TTPtr self, t_symbol *msg, long argc, t_atom *argv)
651 {
652  object_obex_dumpout(self, msg, argc, argv);
653 }
654 
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.
void WrappedScoreClass_new(TTPtr self, long argc, t_atom *argv)
Constructor: Initiate the wrapped object instance.
TTErr send(const TTSymbol aName)
Send a message to this object with no arguments.
Definition: TTObject.cpp:135
void score_filechanged(TTPtr self, char *filename, short path)
void score_edclose(TTPtr self, char **text, long size)
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
void score_edit(TTPtr self, t_symbol *msg, long argc, t_atom *argv)
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_doedit(TTPtr self)
void WrapTTScoreClass(WrappedClassPtr c)
Set up what methods (Max messages) that the wrapped class is to respond to.
void WrappedScoreClass_free(TTPtr self)
Deconstructor: Destroy the object and free memory assigned to it.
void score_read_again(TTPtr self)
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
TTErr registerObserverForNotifications(const TTObject &anObservingObject)
Register an observer.
Definition: TTObject.cpp:155
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
void score_dowrite_again(TTPtr self)
TTObject wrappedObject
The instance of the Jamoma object we are wrapping.
void score_doread_again(TTPtr self)
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
Wraps Jamoma Core classes as objects for PureData.
void score_write(TTPtr self, t_symbol *msg, long argc, t_atom *argv)
void score_read(TTPtr self, t_symbol *msg, long argc, t_atom *argv)
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
std::uint32_t TTUInt32
32 bit unsigned integer
Definition: TTBase.h:178
void score_dowrite(TTPtr self, t_symbol *msg, long argc, t_atom *argv)
void score_doread(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
void score_write_again(TTPtr self)
WrappedModularInstance * WrappedModularInstancePtr
Pointer to a wrapped instance of our object.
[doxygenAppendixC_copyExample]
Definition: TTValue.h:34
TTErr wrapTTModularClassAsPdClass(TTSymbol &ttblueClassName, const char *pdClassName, WrappedClassPtr *c, ModularSpec *specificities)
Wrap a Jamoma class as a Pd class.