Jamoma API  0.6.0.a19
j.snapshot.cpp
Go to the documentation of this file.
1 /** @file
2  *
3  * @ingroup implementationMaxExternals
4  *
5  * @brief j.snapshot : Capture, recall, transform, and manipulate global snapshots
6  *
7  * @details
8  *
9  * @authors Tim Place, Trond Lossius
10  *
11  * @copyright © 2009 by Tim Place @n
12  * This code is licensed under the terms of the "New BSD License" @n
13  * http://creativecommons.org/licenses/BSD/
14  */
15 
16 
17 #include "JamomaForMax.h"
18 
19 class SnapshotParameterValue {
20 public:
21  TTFloat64 value;
22  (t_object*) parameter;
23 
24  SnapshotParameterValue(TTFloat64& f, (t_object*) o):
25  value(f),
26  parameter(o)
27  {;}
28 
29 
30 };
31 
32 // A vector of 64-bit floats used to represent a given snapshot
33 typedef vector<SnapshotParameterValue> Snapshot;
34 typedef Snapshot::iterator SnapshotIter;
35 typedef Snapshot* SnapshotPtr;
36 
37 // A vector (or collection) of snapshots
38 typedef vector<SnapshotPtr> SnapshotCollection;
39 typedef SnapshotCollection::iterator SnapshotCollectionIter;
40 typedef SnapshotCollection* SnapshotCollectionPtr;
41 
42 // Data Structure for this object
43 typedef struct {
44  Object ob;
45  TTNodeDirectoryPtr tree;
46  SnapshotCollectionPtr snapshots;
47  SymbolPtr excludes[128]; // list of parameter and container names to exclude from snapshots
48  TTInt32 excludeSize;
49 } TTModSnapshot;
50 typedef TTModSnapshot* TTModSnapshotPtr;
51 
52 
53 // Prototypes
54 TTPtr TTModSnapshotNew (SymbolPtr name, long argc, t_atom* argv);
55 void TTModSnapshotFree (TTModSnapshotPtr self);
56 t_max_err TTModSnapshotNotify (TTModSnapshotPtr self, SymbolPtr s, SymbolPtr msg, void *sender, void *data);
57 void TTModSnapshotAssist (TTModSnapshotPtr self, void *b, long m, long a, char *s);
58 void TTModSnapshotDump (TTModSnapshotPtr self);
59 void TTModSnapshotStore (TTModSnapshotPtr self, SymbolPtr s, long argc, t_atom* argv);
60 void TTModSnapshotRecall (TTModSnapshotPtr self, SymbolPtr s, long argc, t_atom* argv);
61 
62 
63 // Shared
64 static t_class* sMaxClass;
65 
66 
67 // Class Definition
68 int JAMOMA_EXPORT_MAXOBJ main(void)
69 {
70  t_class* c = class_new("j.snapshot",
71  (method)TTModSnapshotNew,
72  (method)TTModSnapshotFree,
73  sizeof(TTModSnapshot),
74  NULL, A_GIMME, 0);
75 
76  jamoma_init();
77  common_symbols_init();
78 
79  class_addmethod(c, (method)TTModSnapshotNotify, "notify", A_CANT, 0);
80  class_addmethod(c, (method)TTModSnapshotAssist, "assist", A_CANT, 0);
81  class_addmethod(c, (method)TTModSnapshotDump, "dump", 0);
82  class_addmethod(c, (method)TTModSnapshotStore, "store", A_GIMME, 0);
83  class_addmethod(c, (method)TTModSnapshotRecall, "recall", A_GIMME, 0);
84 
85  CLASS_ATTR_SYM_VARSIZE(c, "excludes", 0, TTModSnapshot, excludes, excludeSize, 128);
86 
87  class_register(_sym_box, c);
88  sMaxClass = c;
89  return 0;
90 }
91 
92 
93 #if 0
94 #pragma mark -
95 #pragma mark Life Cycle
96 #endif 0
97 
98 TTPtr TTModSnapshotNew(SymbolPtr name, long argc, t_atom* argv)
99 {
100  TTModSnapshotPtr self = (TTModSnapshotPtr)object_alloc(sMaxClass);
101 
102  if (self) {
103  TTUInt32 i=0;
104 
105  self->snapshots = new SnapshotCollection;
106  self->tree = JamomaDirectory;
107 
108  self->excludes[i++] = gensym("ch");
109  self->excludes[i++] = gensym("view");
110  self->excludes[i++] = gensym("documentation");
111  self->excludeSize = i;
112 
113  attr_args_process(self, argc, argv);
114  }
115  return self;
116 }
117 
118 void TTModSnapshotFree(TTModSnapshotPtr self)
119 {
120  // TODO: leaking memory! -- free of the actuall snapshots held by the pointers!
121  delete self->snapshots;
122 }
123 
124 
125 #if 0
126 #pragma mark -
127 #pragma mark Methods
128 #endif 0
129 
130 t_max_err TTModSnapshotNotify(TTModSnapshotPtr self, SymbolPtr s, SymbolPtr msg, TTPtr sender, TTPtr data)
131 {
132  object_post(SELF, "notification : %s", msg->s_name);
133  return MAX_ERR_NONE;
134 }
135 
136 
137 void TTModSnapshotAssist(TTModSnapshotPtr self, void* b, long msg, long arg, char* dst)
138 {
139  if (msg == ASSIST_INLET) { // inlet
140  if (arg == 0)
141  strcpy(dst, "inlet");
142  }
143  else { // outlet
144  if (arg == 0)
145  strcpy(dst, "outlet");
146  }
147 }
148 
149 
150 void TTModSnapshotDump(TTModSnapshotPtr self)
151 {
152  //jamoma_directory_dump(); // dump all the address of the tree in the Max window
153 }
154 
155 
156 void TTModSnapshotStore(TTModSnapshotPtr self, SymbolPtr s, long argc, t_atom* argv)
157 {
158  TTNodePtr rootNode = self->tree->getRoot();
159  TTValue moduleNodes;
160  TTUInt32 numModules;
161  TTList returnedChildren;
162  TTErr err;
163  SnapshotPtr snapshot = NULL;
164  TTUInt32 snapshotIndex = 0;
165 
166  // snapshot numbers are 1-based for the outside world
167  if (argc && argv)
168  snapshotIndex = atom_getlong(argv) - 1;
169  if (snapshotIndex < 0)
170  snapshotIndex = 0;
171 
172  if (snapshotIndex >= self->snapshots->size()) {
173  if (snapshotIndex >= self->snapshots->capacity()) {
174  self->snapshots->reserve(snapshotIndex+1);
175  }
176  self->snapshots->resize(snapshotIndex+1);
177  }
178  else {
179  snapshot = self->snapshots->at(snapshotIndex);
180  delete snapshot;
181  snapshot = NULL;
182  }
183  snapshot = new Snapshot;
184 
185 
186  err = rootNode->getChildren(S_WILDCARD, S_WILDCARD, returnedChildren);
187 
188  returnedChildren.assignToValue(moduleNodes);
189  numModules = moduleNodes.getSize();
190  for (TTUInt32 i=0; i<numModules; i++) {
191  TTNodePtr module = NULL;
192  TTSymbol type;
193 
194  moduleNodes.get(i, (TTPtr*)(&module));
195  if (module) {
196  if (module->getObject()) {
197 
198  type = module->getObject()->getName();
199  if (type == TTSymbol("Container")) {
200  TTValue parameterNodes;
201  TTUInt32 numParameters;
202 
203  post(" Module: %s", module->getName().c_str());
204  err = module->getChildren(S_WILDCARD, S_WILDCARD, returnedChildren);
205  returnedChildren.assignToValue(parameterNodes);
206  numParameters = parameterNodes.getSize();
207  for (TTUInt32 i=0; i<numParameters; i++) {
208  TTNodePtr parameter = NULL;
209  TTSymbol childType;
210 
211  parameterNodes.get(i, (TTPtr*)(&parameter));
212  if (parameter) {
213  bool exclude = false;
214  // first check for the name in the excludes list
215  for (TTInt32 e=0; e < self->excludeSize; e++) {
216  TTSymbol s1 = parameter->getName();
217  TTSymbol s2 = TTSymbol(self->excludes[e]->s_name);
218 
219  if (s1 == s2) {
220  exclude = true;
221  break;
222  }
223  }
224  if (exclude)
225  continue;
226 
227  // then make sure it is actually a parameter
228  if (parameter->getObject()) {
229  childType = parameter->getObject()->getName();
230  if (childType == TTSymbol("Data")) { // FIXME: this name sucks for the type.
231  ObjectPtr maxObject = (t_object*)parameter->getObject();
232  SymbolPtr maxType = object_attr_getsym(maxObject, SymbolGen("type"));
233 
234  // we're ignoring non-int, non-float params for the time being
235  if (maxType == SymbolGen("decimal") || maxType == SymbolGen("integer")) {
236  TTFloat64 value = object_attr_getfloat(maxObject, SymbolGen("value"));
237  SnapshotParameterValue spv(value, maxObject);
238 
239  snapshot->push_back(spv);
240  post(" parameter: %s -- value: %lf", parameter->getName().c_str(), value);
241  }
242  }
243  // FIXME: the code below sucks big-time -- need to redo as a recursive function
244  else if (childType == TTSymbol("container")) {
245  TTValue containerNodes;
246  TTUInt32 numParameters2;
247  TTList containerChildren;
248 
249  post(" Container: %s", parameter->getName().c_str());
250  err = parameter->getChildren(TTSymbol("*"), TTSymbol("*"), containerChildren);
251  containerChildren.assignToValue(containerNodes);
252  numParameters2 = containerNodes.getSize();
253  for (TTUInt32 i=0; i<numParameters2; i++) {
254  TTNodePtr parameter2 = NULL;
255  TTSymbol childType2;
256 
257  containerNodes.get(i, (TTPtr*)(&parameter2));
258  if (parameter2) {
259  bool exclude = false;
260  // first check for the name in the excludes list
261  for (TTInt32 e=0; e < self->excludeSize; e++) {
262  TTSymbol s1 = parameter2->getName();
263  TTSymbol s2 = TTSymbol(self->excludes[e]->s_name);
264 
265  if (s1 == s2) {
266  exclude = true;
267  break;
268  }
269  }
270  if (exclude)
271  continue;
272 
273  // then make sure it is actually a parameter
274  childType2 = parameter2->getType();
275  if (childType2 == TTSymbol("subscribe_parameter")) { // FIXME: this name sucks for the type.
276  ObjectPtr maxObject = (t_object*)parameter2->getObject();
277  SymbolPtr maxType = object_attr_getsym(maxObject, SymbolGen("type"));
278 
279  // we're ignoring non-int, non-float params for the time being
280  if (maxType == SymbolGen("decimal") || maxType == SymbolGen("integer")) {
281  TTFloat64 value = object_attr_getfloat(maxObject, SymbolGen("value"));
282  SnapshotParameterValue spv(value, maxObject);
283 
284  snapshot->push_back(spv);
285  post(" parameter: %s -- value: %lf", parameter2->getName().c_str(), value);
286  }
287  }
288  }
289  }
290  }
291  }
292  }
293  }
294  }
295  }
296  }
297  (*self->snapshots)[snapshotIndex] = snapshot;
298 }
299 
300 
301 void TTModSnapshotRecallOne(const SnapshotParameterValue& spv)
302 {
303  object_method(spv.parameter, _sym_float, spv.value);
304 }
305 
306 
307 void TTModSnapshotRecall(TTModSnapshotPtr self, SymbolPtr s, long argc, t_atom* argv)
308 {
309  if (!argc || !argv)
310  return;
311 
312  // straight recall
313  if (argc == 1) {
314  SnapshotPtr snapshot;
315  TTUInt32 snapshotIndex = atom_getlong(argv) - 1;
316 
317  if (snapshotIndex < 0)
318  snapshotIndex = 0;
319 
320  if (snapshotIndex >= self->snapshots->size()) {
321  object_error(SELF, "preset recall out of range");
322  return;
323  }
324  snapshot = (*self->snapshots)[snapshotIndex];
325  if (snapshot)
326  for_each((*snapshot).begin(), (*snapshot).end(), TTModSnapshotRecallOne);
327  else
328  object_error(SELF, "invalid preset recall requested");
329  }
330 
331  // interpolate between any two
332  else if (argc == 3) {
333  SnapshotPtr snapshotA;
334  SnapshotPtr snapshotB;
335  TTUInt32 snapshotIndexA = atom_getlong(argv+0) - 1;
336  TTUInt32 snapshotIndexB = atom_getlong(argv+1) - 1;
337  TTUInt32 snapshotSizeA = atom_getlong(argv+0);
338  TTUInt32 snapshotSizeB = atom_getlong(argv+1);
339  TTFloat32 position = atom_getfloat(argv+2);
340 
341  if (snapshotIndexA < 0)
342  snapshotIndexA = 0;
343  if (snapshotIndexB < 0)
344  snapshotIndexB = 0;
345 
346  if (snapshotIndexA >= self->snapshots->size() ||
347  snapshotIndexB >= self->snapshots->size())
348  {
349  object_error(SELF, "preset recall out of range");
350  return;
351  }
352 
353  snapshotA = (*self->snapshots)[snapshotIndexA];
354  snapshotB = (*self->snapshots)[snapshotIndexB];
355  snapshotSizeA = snapshotA->size();
356  snapshotSizeB = snapshotB->size();
357 
358  if (snapshotSizeA != snapshotSizeB) {
359  object_error(SELF, "preset recall -- cannot interpolate between snapshots of unequal size");
360  return;
361  }
362 
363  for (TTUInt32 i=0; i<snapshotSizeA; i++) {
364  if ( (*snapshotA)[i].parameter == (*snapshotB)[i].parameter ) {
365  TTFloat32 f = ((*snapshotA)[i].value * (1.0 - position)) + ((*snapshotB)[i].value * (position));
366  object_method((*snapshotA)[i].parameter, _sym_float, f);
367  }
368  }
369  }
370 
371  // wieghted interpolation
372  else if (argc > 3) {
373  TTUInt32 size;
374  TTUInt32 ac = argc;
375  bool boundsCheckFailed = false;
376  SnapshotPtr snapshot;
377  Snapshot interpolatedResult;
378  TTFloat32 weight;
379 
380  // check bounds
381  if (ac > self->snapshots->size()) {
382  object_error(SELF, "recall can not interpolate -- not enough snapshots for provided weights");
383  return;
384  }
385 
386  snapshot = (*self->snapshots)[0];
387  if (!snapshot) {
388  object_error(SELF, "recall can not interpolate -- bogus initial snapshot");
389  return;
390  }
391 
392  size = snapshot->size();
393  for (int i=1; i<argc; i++) {
394  if (!(*self->snapshots)[i] || (*self->snapshots)[i]->size() != size) {
395  boundsCheckFailed = true;
396  break;
397  }
398  }
399  if (boundsCheckFailed) {
400  object_error(SELF, "recall can not interpolate -- snapshots are of unequal size, or there is a missing snapshot in the sequence");
401  return;
402  }
403 
404  interpolatedResult.reserve(size);
405  for (int i=0; i<argc; i++) {
406  snapshot = (*self->snapshots)[i];
407  weight = atom_getfloat(argv+i);
408  if (i==0) {
409  interpolatedResult.insert(interpolatedResult.begin(), snapshot->begin(), snapshot->end());
410  // TODO: There must be a better way than this nested loop using some variant for for_each() or something...
411  for (TTUInt32 j=0; j<size; j++) {
412  interpolatedResult[j].value *= weight;
413  }
414  }
415  else {
416  // TODO: There must be a better way than this nested loop using some variant for for_each() or something...
417  for (TTUInt32 j=0; j<size; j++) {
418  interpolatedResult[j].value += ((*snapshot)[j].value * weight);
419  }
420  }
421  }
422  for_each(interpolatedResult.begin(), interpolatedResult.end(), TTModSnapshotRecallOne);
423  }
424 }
425 
TTUInt16 getSize() const
DEPRECATED.
Definition: TTValue.h:521
TTSymbol & getName()
Get the name of the node.
Definition: TTNode.cpp:286
We build a directory of TTNodes, and you can request a pointer for any TTNode, or add an observer to ...
Definition: TTNode.h:59
TTObject & getObject()
Get the object binded by this node.
Definition: TTNode.cpp:468
double TTFloat64
64 bit floating point number
Definition: TTBase.h:188
void * TTPtr
A generic pointer.
Definition: TTBase.h:248
int JAMOMA_EXPORT_MAXOBJ main(void)
Set up this class as a Max external the first time an object of this kind is instantiated.
Definition: j.snapshot.cpp:68
The TTSymbol class is used to represent a string and efficiently pass and compare that string...
Definition: TTSymbol.h:26
float TTFloat32
32 bit floating point number
Definition: TTBase.h:187
void get(const TTUInt16 index, T &returnedElementValue) const
DEPRECATED.
Definition: TTValue.h:591
Various utilities for interfacing with Max that are not specific to JamomaModular as such...
const char * c_str() const
Return a pointer to the internal string as a C-string.
Definition: TTSymbol.h:77
std::int32_t TTInt32
32 bit signed integer
Definition: TTBase.h:177
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
TTErr getChildren(TTSymbol &name, TTSymbol &instance, TTList &returnedChildren)
Get a linklist of children of the node : select them by name and instance (use wilcards to select the...
Definition: TTNode.cpp:301
We build a tree of TTNodes, and you can request a pointer for any TTNode, or add an observer to any T...
[doxygenAppendixC_copyExample]
Definition: TTValue.h:34