Jamoma API  0.6.0.a19
Jamoma.cpp
1 // Language Bindings to Make the Jamoma Runtime accessible via Ruby
2 // Copyright © 2009, Timothy Place
3 // License: New BSD License -- http://creativecommons.org/licenses/BSD/
4 
5 #include "TTAudioGraphAPI.h"
6 #include "ruby.h"
7 
8 
9 //
10 class TTRubyInstance {
11 public:
12 // TTAudioObjectBasePtr obj;
13  TTAudioObject obj;
14  TTHashPtr parameterNames; // cache of parameter names, mapped from lowercase (ruby) to uppercase (TT)
15  TTHashPtr messageNames; // cache of parameter names, mapped from lowercase (ruby) to uppercase (TT)
16 
17  TTRubyInstance(const TTSymbol name, const TTValue args) :
18  obj(name, args)
19  {
20  ;
21  }
22 };
23 
24 
25 //
26 class TTAudioInstance {
27 public:
28 // TTAudioGraphObjectBasePtr obj;
29  TTAudioGraphObject obj;
30  TTHashPtr parameterNames; // cache of parameter names, mapped from lowercase (ruby) to uppercase (TT)
31  TTHashPtr messageNames; // cache of parameter names, mapped from lowercase (ruby) to uppercase (TT)
32 
33  TTAudioInstance(const TTValue args)
34  {
35  try {
36  obj = TTAudioGraphObject(args);
37  }
38  catch (...) {
39  std::cout << "Bogus Crap Happened Bros." << std::endl;
40  }
41  }
42 };
43 
44 
45 typedef VALUE (*TTRubyMethod)(...);
46 //#define TTRubyMethod
47 
48 
49 // Prototypes
50 extern "C" {
51  void Init_Jamoma();
52 
53  VALUE TTRubyInitialize(VALUE self, VALUE className);
54  VALUE TTRubyGetMessages(VALUE self);
55  VALUE TTRubySendMessage(int argc, VALUE* argv, VALUE self);
56  VALUE TTRubyGetAttributes(VALUE self);
57  VALUE TTRubySetAttribute(VALUE self, VALUE attributeName, VALUE attributeValue);
58  VALUE TTRubyGetAttribute(VALUE self, VALUE attributeName);
59  VALUE TTRubyCalculate(VALUE self, VALUE x);
60 
61  VALUE TTAudioInitialize(int argc, VALUE* argv, VALUE self);
62  VALUE TTAudioGetMessages(VALUE self);
63  VALUE TTAudioSendMessage(int argc, VALUE* argv, VALUE self);
64  VALUE TTAudioGetAttributes(VALUE self);
65  VALUE TTAudioSetAttribute(VALUE self, VALUE attributeName, VALUE attributeValue);
66  VALUE TTAudioGetAttribute(VALUE self, VALUE attributeName);
67  VALUE TTAudioReset(VALUE self);
68  VALUE TTAudioConnect(int argc, VALUE* argv, VALUE self);
69  VALUE TTAudioDrop(int argc, VALUE* argv, VALUE self);
70  VALUE TTAudioExportMax(VALUE self, VALUE pathToExportFile);
71  VALUE TTAudioExportCpp(VALUE self, VALUE pathToExportFile);
72 }
73 
74 
75 // Globals and Statics
76 VALUE TTRuby_class;
77 TTHashPtr gTTRubyInstances = NULL;
78 //std::unordered_map<TTPtr, TTValue> gTTRubyInstances;
79 
80 VALUE TTAudio_class;
81 TTHashPtr gTTAudioInstances = NULL;
82 
83 
84 /*****************************************************************************************************/
85 // Class Definition
86 
87 void Init_Jamoma()
88 {
89  VALUE c;
90 
91  TTFoundationInit();
92 
93  c = rb_define_class("TTObject", rb_cObject);
94 
95  rb_define_method(c, "initialize", TTRubyMethod(TTRubyInitialize), 1); // called to initialize a new object that has been created or cloned
96  rb_define_method(c, "messages?", TTRubyMethod(TTRubyGetMessages), 0);
97  rb_define_method(c, "send", TTRubyMethod(TTRubySendMessage), -1); // send a message to the wrapped object
98  rb_define_method(c, "attributes?", TTRubyMethod(TTRubyGetAttributes), 0);
99  rb_define_method(c, "set", TTRubyMethod(TTRubySetAttribute), 2); // set attribute value
100  rb_define_method(c, "get", TTRubyMethod(TTRubyGetAttribute), 1); // get attribute value
101  rb_define_method(c, "calculate", TTRubyMethod(TTRubyCalculate), 1);
102 
103  TTRuby_class = c;
104  gTTRubyInstances = new TTHash;
105 
106 
107  // AUDIO
108 
109  TTAudioGraphInit();
110 
111  c = rb_define_class("TTAudio", rb_cObject);
112 
113  rb_define_method(c, "initialize", TTRubyMethod(TTAudioInitialize), -1); // called to initialize a new object that has been created or cloned
114  rb_define_method(c, "messages?", TTRubyMethod(TTAudioGetMessages), 0);
115  rb_define_method(c, "send", TTRubyMethod(TTAudioSendMessage), -1); // send a message to the wrapped object
116  rb_define_method(c, "attributes?", TTRubyMethod(TTAudioGetAttributes), 0);
117  rb_define_method(c, "set", TTRubyMethod(TTAudioSetAttribute), 2); // set attribute value
118  rb_define_method(c, "get", TTRubyMethod(TTAudioGetAttribute), 1); // get attribute value
119  rb_define_method(c, "reset_audio", TTRubyMethod(TTAudioReset), 0); // reset audio graph connections
120  rb_define_method(c, "connect_audio", TTRubyMethod(TTAudioConnect), -1); // connect an output of another object to our input
121  rb_define_method(c, "drop_audio", TTRubyMethod(TTAudioDrop), -1); // disconnect an output of another object from our input
122  rb_define_method(c, "export_max", TTRubyMethod(TTAudioExportMax), 1); // reset audio graph connections
123  rb_define_method(c, "export_cpp", TTRubyMethod(TTAudioExportCpp), 1); // reset audio graph connections
124 
125  TTAudio_class = c;
126  gTTAudioInstances = new TTHash;
127 }
128 
129 
130 /*****************************************************************************************************/
131 // Life Cycle
132 
133 // See pg 292 for an example of how to setup the message binding for this one
134 // VALUE TTRubyAlloc(VALUE ttruby_class)
135 
136 VALUE TTRubyInitialize(VALUE self, VALUE className)
137 {
138  TTValue v;
139  TTValue args;
140  TTErr err = kTTErrNone;
141  VALUE classNameStr = StringValue(className);
142  TTSymbol classNameTTStr(RSTRING_PTR(classNameStr));
143  long n;
144  TTValue names;
145  TTSymbol aName = kTTSymEmpty;
146  TTString nameString;
147  TTRubyInstance* instance;
148  args.clear();
149 
150  try {
151 // right now we just leak all of our instances (oops), but when we do free them correctly we don't want to free the environment!
152 // if (classNameTTStr == "environment")
153 // instance->obj = (TTAudioObjectBase*)ttEnvironment;
154 
155  instance = new TTRubyInstance(classNameTTStr, args);
156  }
157  catch (...) {
158  std::cout << "Error loading object " << classNameTTStr.c_str() << std::endl;
159  return 0;
160  }
161 
162  instance->parameterNames = new TTHash; // TODO: need to free this
163  instance->obj.attributes(names);
164  n = names.size();
165  for (int i=0; i<n; i++) {
166  names.get(i, aName);
167  nameString = aName.c_str();
168  {
169  v = aName;
170  instance->parameterNames->append(TTSymbol(nameString.c_str()), v);
171  }
172  }
173 
174  instance->messageNames = new TTHash; // TODO: need to free this
175  instance->obj.messages(names);
176  n = names.size();
177  for (int i=0; i<n; i++) {
178  names.get(i, aName);
179  nameString = aName.c_str();
180  {
181  v = aName;
182  instance->messageNames->append(TTSymbol(nameString.c_str()), v);
183  }
184  }
185 
186  v.resize(1);
187  v.set(0, TTPtr(instance));
188  gTTRubyInstances->append(TTPtr(self), v);
189  return self;
190 }
191 
192 // VALUE TTRubyInitializeCopy(VALUE self, VALUE orig)
193 
194 // See page 285 about wrapping and freeing structs
195 
196 
197 /*****************************************************************************************************/
198 // Methods
199 
200 VALUE TTRubyGetMessages(VALUE self)
201 {
202  TTRubyInstance* instance = NULL;
203  TTErr err = kTTErrNone;
204  TTValue v;
205  VALUE returnValue = rb_float_new(0.0);
206  TTSymbol s = kTTSymEmpty;
207  TTCString c;
208  TTUInt16 size;
209 
210  err = gTTRubyInstances->lookup(TTPtr(self), v);
211  if (!err) {
212  instance = (TTRubyInstance*)TTPtr(v[0]);
213  if (instance) {
214  TTValue names;
215 
216  instance->messageNames->getKeys(names);
217  //instance->obj->getMessageNames(v);
218  size = names.size();
219  returnValue = rb_ary_new2(size);
220  for (TTUInt16 i=0; i<size; i++) {
221  names.get(i, s);
222  c = (TTCString)s.c_str();
223  rb_ary_store(returnValue, i, rb_str_new(c, strlen(c)));
224  }
225  }
226  }
227  return returnValue;
228 }
229 
230 VALUE TTRubySendMessage(int argc, VALUE* argv, VALUE self)
231 {
232  TTRubyInstance* instance = NULL;
233  TTErr err = kTTErrNone;
234  VALUE messageNameStr;
235  VALUE messageArgStr;
236  TTValue v_in;
237  TTValue v_out;
238  TTValue v_temp;
239 
240  if (argc < 1) {
241  std::cout << "ERROR -- TTRuby.send requires at least 1 argument (the name of the message to send)" << std::endl;
242  goto bye;
243  }
244 
245  messageNameStr = StringValue(argv[0]);
246  err = gTTRubyInstances->lookup(TTPtr(self), v_temp);
247  if (!err) {
248  instance = (TTRubyInstance*)TTPtr(v_temp[0]);
249  if (instance) {
250  TTSymbol messageName = kTTSymEmpty;
251  TTValue messageNameValue;
252 
253  messageName = RSTRING_PTR(messageNameStr);
254  instance->messageNames->lookup(messageName, messageNameValue);
255  messageName = messageNameValue[0];
256 
257 // if (argc == 1) { // no arguments...
258 // err = instance->obj->sendMessage(messageName);
259 // }
260 // else { // we have arguments...
261  v_in.clear();
262  v_out.clear();
263 
264  for (int i=1; i<argc; i++) {
265  int t = TYPE(argv[i]);
266 
267  //std::cout << "the type of the message arg is " << t << std::endl;
268  switch (t) {
269  case T_FLOAT:
270  v_in.append(NUM2DBL(argv[i]));
271  break;
272  case T_FIXNUM:
273  v_in.append((int)FIX2LONG(argv[i]));
274  break;
275  case T_BIGNUM:
276  v_in.append((TTInt64)NUM2LL(argv[i]));
277  break;
278  case T_STRING:
279  messageArgStr = StringValue(argv[i]);
280  v_in.append(TTSymbol(RSTRING_PTR(messageArgStr)));
281  break;
282  case T_ARRAY:
283  std::cout << "TTError: Array arguments for messages not yet supported in Ruby" << std::endl;
284  err = kTTErrGeneric;
285  break;
286  case T_OBJECT:
287  std::cout << "TTError: Object arguments for messages not yet supported in Ruby" << std::endl;
288  err = kTTErrGeneric;
289  break;
290  default:
291  // assume no arguments for now...
292  break;
293  }
294  }
295 
296  if (!err) {
297  err = instance->obj.send(messageName, v_in, v_out);
298  }
299 // }
300 
301  if (err)
302  std::cout << "TTRubySendMessage: Error " << err << std::endl;
303  else {
304  // return an array -- the first item is the error code
305  // additional values may follow
306  int size = v_out.size();
307  int i;
308  VALUE ret = rb_ary_new2(size + 1);
309 
310  rb_ary_store(ret, 0, err);
311  for (i=0; i<size; i++) {
312 
313  // TODO: support other types
314 
315  if (v_out[i].type() == kTypeFloat64 || v_out[0].type() == kTypeFloat32) {
316 
317  TTFloat64 f;
318  VALUE fv;
319 
320  v_out.get(i, f);
321  fv = rb_float_new(f);
322  //std::cout << "return value " << i << " is " << f << std::endl;
323 
324  rb_ary_store(ret, i+1, fv);
325  }
326  else if (v_out[i].type() == kTypeObject)
327  std::cout << "objects as return values are not yet supported" << std::endl;
328  else if (v_out[i].type() == kTypeSymbol) {
329  TTSymbol sp = kTTSymEmpty;
330  TTCString c;
331 
332  v_out.get(i, sp);
333  if (sp) {
334  c = (TTCString)sp.c_str();
335  rb_ary_store(ret, i+1, rb_str_new(c, strlen(c)));
336  }
337  }
338  else { // assuming int for now, should probably actually check it
339  TTInt32 l;
340  VALUE lv;
341 
342  v_out.get(i, l);
343  lv = rb_int_new(l);
344  rb_ary_store(ret, i+1, lv);
345  }
346  }
347  return ret;
348  }
349  }
350  }
351 bye:
352  return 0;
353 }
354 
355 
356 VALUE TTRubyGetAttributes(VALUE self)
357 {
358  TTRubyInstance* instance = NULL;
359  TTErr err = kTTErrNone;
360  TTValue v;
361  VALUE returnValue = rb_float_new(0.0);
362  TTSymbol s = kTTSymEmpty;
363  TTCString c;
364  TTUInt16 size;
365 
366  err = gTTRubyInstances->lookup(TTPtr(self), v);
367  if (!err) {
368  instance = (TTRubyInstance*)TTPtr(v[0]);
369  if (instance) {
370  TTValue names;
371 
372  instance->parameterNames->getKeys(names);
373  //instance->obj->getAttributeNames(v);
374  size = names.size();
375  returnValue = rb_ary_new2(size);
376  for (TTUInt16 i=0; i<size; i++) {
377  names.get(i, s);
378  c = (TTCString)s.c_str();
379  rb_ary_store(returnValue, i, rb_str_new(c, strlen(c)));
380  }
381  }
382  }
383  return returnValue;
384 }
385 
386 
387 VALUE TTRubySetAttribute(VALUE self, VALUE attributeName, VALUE attributeValue)
388 {
389  TTRubyInstance* instance = NULL;
390  TTErr err = kTTErrNone;
391  VALUE attributeNameStr = StringValue(attributeName);
392  VALUE attributeValueStr;
393  TTValue v;
394 
395  err = gTTRubyInstances->lookup(TTPtr(self), v);
396  if (!err) {
397  instance = (TTRubyInstance*)TTPtr(v[0]);
398  if (instance) {
399  int t = TYPE(attributeValue);
400 
401  v.clear();
402  //std::cout << "the type of the attr arg is " << t << std::endl;
403  switch (t) {
404  case T_FLOAT:
405  v.append(NUM2DBL(attributeValue));
406  break;
407  case T_FIXNUM:
408  v.append((int)FIX2LONG(attributeValue));
409  break;
410  case T_BIGNUM:
411  v.append((TTInt64)NUM2LL(attributeValue));
412  break;
413  case T_STRING:
414  attributeValueStr = StringValue(attributeValue);
415  v.append(TTSymbol(RSTRING_PTR(attributeValueStr)));
416  break;
417  case T_ARRAY:
418  std::cout << "TTError: Array arguments for attributes not yet supported in Ruby" << std::endl;
419  err = kTTErrGeneric;
420  break;
421  case T_OBJECT:
422  std::cout << "TTError: Object arguments for attributes not yet supported in Ruby" << std::endl;
423  err = kTTErrGeneric;
424  break;
425  default:
426  std::cout << "TTError: Unknown type for arguments to attribute" << std::endl;
427  err = kTTErrGeneric;
428  break;
429  }
430  if (!err) {
431  TTSymbol parameterName = kTTSymEmpty;
432  TTValue parameterNameValue;
433 
434  parameterName = RSTRING_PTR(attributeNameStr);
435  instance->parameterNames->lookup(parameterName, parameterNameValue);
436  parameterNameValue.get(0, parameterName);
437 
438  err = instance->obj.set(parameterName, v);
439  }
440  if (err)
441  std::cout << "TTRubySetAttribute: Error " << err << std::endl;
442  }
443  }
444  return 0;
445 }
446 
447 
448 VALUE TTRubyGetAttribute(VALUE self, VALUE attributeName)
449 {
450  TTRubyInstance* instance = NULL;
451  TTErr err = kTTErrNone;
452  VALUE attributeNameStr = StringValue(attributeName);
453  //VALUE attributeValueStr;
454  TTValue v;
455  VALUE returnValue = rb_float_new(0.0);
456  TTSymbol s = kTTSymEmpty;
457  TTCString c;
458 
459  err = gTTRubyInstances->lookup(TTPtr(self), v);
460  if (!err) {
461  instance = (TTRubyInstance*)TTPtr(v[0]);
462  if (instance) {
463  TTSymbol parameterName = kTTSymEmpty;
464  TTValue parameterNameValue;
465 
466  parameterName = RSTRING_PTR(attributeNameStr);
467  instance->parameterNames->lookup(parameterName, parameterNameValue);
468  parameterNameValue.get(0, parameterName);
469 
470  err = instance->obj.get(parameterName, v);
471  if (err) {
472  std::cout << "TTRubyGetAttribute: Error " << err << std::endl;
473  goto out;
474  }
475 
476  // TODO: not handling array attrs yet...
477 
478  switch (v[0].type()) {
479  case kTypeFloat64:
480  case kTypeFloat32:
481  returnValue = rb_float_new(v);
482  break;
483  case kTypeInt8:
484  case kTypeUInt8:
485  case kTypeInt16:
486  case kTypeUInt16:
487  case kTypeInt32:
488  case kTypeUInt32:
489  returnValue = INT2NUM(v);
490  break;
491  case kTypeInt64:
492  case kTypeUInt64:
493  returnValue = LL2NUM((TTInt64)v);
494  break;
495  case kTypeBoolean:\
496  returnValue = TTBoolean(v);
497  break;
498  case kTypeSymbol:
499  s = v;
500  c = (TTCString)s.c_str();
501  returnValue = rb_str_new(c, strlen(c));
502  break;
503 
504  case kTypeNone:
505  case kTypeObject:
506  case kTypePointer:
507  case kTypeString:
508  case kTypeLocalValue:
509  case kNumTTDataTypes:
510  default:
511  break;
512  }
513  }
514  }
515 out:
516  return returnValue;
517 }
518 
519 
520 VALUE TTRubyCalculate(VALUE self, VALUE x)
521 {
522  TTRubyInstance* instance = NULL;
523  TTErr err = kTTErrNone;
524  TTValue v;
525  VALUE returnValue = rb_float_new(0.0);
526 
527  err = gTTRubyInstances->lookup(TTPtr(self), v);
528  if (!err) {
529  instance = (TTRubyInstance*)TTPtr(v[0]);
530  if (instance) {
531  TTFloat64 fx = NUM2DBL(x);
532  TTFloat64 fy = 0.0;
533 
534  err = instance->obj.calculate(fx, fy);
535  returnValue = rb_float_new(fy);
536  }
537  }
538  return returnValue;
539 }
540 
541 
542 
543 /**************************************************************************************/
544 #pragma mark -
545 #pragma mark Audio Graph Support
546 
547 
548 //VALUE TTAudioInitialize(VALUE self, VALUE className)
549 VALUE TTAudioInitialize(int argc, VALUE* argv, VALUE self)
550 {
551  if (argc < 1) {
552  std::cout << "ERROR -- TTAudio requires at least 1 argument (the name of the object class to create)" << std::endl;
553  return 0;
554  }
555 
556  VALUE messageArgStr;
557  TTValue args;
558  TTErr err = kTTErrNone;
559 
560  args.clear();
561  for (int i=0; i<argc; i++) {
562  int t = TYPE(argv[i]);
563 
564  //std::cout << "the type of the message arg is " << t << std::endl;
565  switch (t) {
566  case T_FLOAT:
567  args.append(NUM2DBL(argv[i]));
568  break;
569  case T_FIXNUM:
570  args.append((int)FIX2LONG(argv[i]));
571  break;
572  case T_BIGNUM:
573  args.append((TTInt64)NUM2LL(argv[i]));
574  break;
575  case T_STRING:
576  messageArgStr = StringValue(argv[i]);
577  args.append(TTSymbol(RSTRING_PTR(messageArgStr)));
578  break;
579  case T_ARRAY:
580  std::cout << "TTError: Array arguments for messages not yet supported in Ruby" << std::endl;
581  err = kTTErrGeneric;
582  break;
583  case T_OBJECT:
584  std::cout << "TTError: Object arguments for messages not yet supported in Ruby" << std::endl;
585  err = kTTErrGeneric;
586  break;
587  default:
588  // assume no arguments for now...
589  break;
590  }
591  }
592 
593  TTAudioInstance* instance = new TTAudioInstance(args);
594  TTValue v;
595  long n;
596  TTValue names;
597  TTSymbol aName = kTTSymEmpty;
598  TTString nameString;
599 
600  //err = TTObjectBaseInstantiate(RSTRING_PTR(classNameStr), &instance->obj, args);
601  //err = TTObjectBaseInstantiate("audio.object", (TTObjectBasePtr*)&instance->obj, );
602 
603  if (!err) {
604  instance->parameterNames = new TTHash; // TODO: need to free this
605 // instance.obj->getUnitGenerator()->getAttributeNames(names);
606  instance->obj.attributes(names);
607  n = names.size();
608  for (int i=0; i<n; i++) {
609  names.get(i, aName);
610  nameString = aName.c_str();
611  {
612  v = aName;
613  instance->parameterNames->append(TTSymbol(nameString.c_str()), v);
614  }
615  }
616 
617  instance->messageNames = new TTHash; // TODO: need to free this
618 // instance.obj->getUnitGenerator()->getMessageNames(names);
619  instance->obj.messages(names);
620  n = names.size();
621  for (int i=0; i<n; i++) {
622  names.get(i, aName);
623  nameString = aName.c_str();
624  {
625  v = aName;
626  instance->messageNames->append(TTSymbol(nameString.c_str()), v);
627  }
628  }
629 
630  v.resize(1);
631  v[0] = TTPtr(instance);
632  gTTAudioInstances->append(TTPtr(self), v);
633  return self;
634  }
635  else {
636  std::cout << "TTObjectBaseInstantiate failed to create object" << std::endl;
637  return 0;
638  }
639 }
640 
641 
642 VALUE TTAudioGetMessages(VALUE self)
643 {
644  TTAudioInstance* instance = NULL;
645  TTErr err = kTTErrNone;
646  TTValue v;
647  VALUE returnValue = rb_float_new(0.0);
648  TTSymbol s = kTTSymEmpty;
649  TTCString c;
650  TTUInt16 size;
651 
652  err = gTTAudioInstances->lookup(TTPtr(self), v);
653  if (!err) {
654  instance = (TTAudioInstance*)TTPtr(v[0]);
655  if (instance) {
656  TTValue names;
657 
658  instance->messageNames->getKeys(names);
659  //instance->obj->getUnitGenerator()->getMessageNames(v);
660  size = names.size();
661  returnValue = rb_ary_new2(size);
662  for (TTUInt16 i=0; i<size; i++) {
663  names.get(i, s);
664  c = (TTCString)s.c_str();
665  rb_ary_store(returnValue, i, rb_str_new(c, strlen(c)));
666  }
667  }
668  }
669  return returnValue;
670 }
671 
672 
673 VALUE TTAudioSendMessage(int argc, VALUE* argv, VALUE self)
674 {
675  TTAudioInstance* instance = NULL;
676  TTErr err = kTTErrNone;
677  VALUE messageNameStr;
678  VALUE messageArgStr;
679  TTValue v_in;
680  TTValue v_out;
681  TTValue v_temp;
682 
683  if (argc < 1) {
684  std::cout << "ERROR -- TTRuby.send requires at least 1 argument (the name of the message to send)" << std::endl;
685  goto bye;
686  }
687 
688  messageNameStr = StringValue(argv[0]);
689  err = gTTAudioInstances->lookup(TTPtr(self), v_temp);
690  if (!err) {
691  instance = (TTAudioInstance*)TTPtr(v_temp[0]);
692  if (instance) {
693  TTSymbol messageName = kTTSymEmpty;
694  TTValue messageNameValue;
695 
696  messageName = RSTRING_PTR(messageNameStr);
697  instance->messageNames->lookup(messageName, messageNameValue);
698  messageNameValue.get(0, messageName);
699 
700 // if (argc == 1) { // no arguments...
701 // err = instance->obj->getUnitGenerator()->sendMessage(messageName);
702 /// }
703 // else { // we have arguments...
704  v_in.clear();
705  v_out.clear();
706 
707  for (int i=1; i<argc; i++) {
708  int t = TYPE(argv[i]);
709 
710  //std::cout << "the type of the message arg is " << t << std::endl;
711  switch (t) {
712  case T_FLOAT:
713  v_in.append(NUM2DBL(argv[i]));
714  break;
715  case T_FIXNUM:
716  v_in.append((int)FIX2LONG(argv[i]));
717  break;
718  case T_BIGNUM:
719  v_in.append((TTInt64)NUM2LL(argv[i]));
720  break;
721  case T_STRING:
722  messageArgStr = StringValue(argv[i]);
723  v_in.append(TTSymbol(RSTRING_PTR(messageArgStr)));
724  break;
725  case T_ARRAY:
726  std::cout << "TTError: Array arguments for messages not yet supported in Ruby" << std::endl;
727  err = kTTErrGeneric;
728  break;
729  case T_OBJECT:
730  std::cout << "TTError: Object arguments for messages not yet supported in Ruby" << std::endl;
731  err = kTTErrGeneric;
732  break;
733  default:
734  // assume no arguments for now...
735  break;
736  }
737  }
738 
739  if (!err) {
740  err = instance->obj.send(messageName, v_in, v_out);
741  }
742 // }
743 
744  if (err)
745  std::cout << "TTAudioSendMessage ('" << RSTRING_PTR(messageNameStr) << "'): Error " << err << std::endl;
746  else {
747  // return an array -- the first item is the error code
748  // additional values may follow
749  int size = v_out.size();
750  int i;
751  VALUE ret = rb_ary_new2(size + 1);
752 
753  rb_ary_store(ret, 0, err);
754  for (i=0; i<size; i++) {
755 
756  // TODO: support other types
757 
758  if (v_out[i].type() == kTypeFloat64 || v_out[0].type() == kTypeFloat32) {
759 
760  TTFloat64 f;
761  VALUE fv;
762 
763  v_out.get(i, f);
764  fv = rb_float_new(f);
765  //std::cout << "return value " << i << " is " << f << std::endl;
766 
767  rb_ary_store(ret, i+1, fv);
768  }
769  else if (v_out[i].type() == kTypeObject)
770  std::cout << "objects as return values are not yet supported" << std::endl;
771  else if (v_out[i].type() == kTypeSymbol) {
772  TTSymbol sp = kTTSymEmpty;
773  TTCString c;
774 
775  v_out.get(i, sp);
776  if (sp) {
777  c = (TTCString)sp.c_str();
778  rb_ary_store(ret, i+1, rb_str_new(c, strlen(c)));
779  }
780  }
781  else { // assuming int for now, should probably actually check it
782  TTInt32 l;
783  VALUE lv;
784 
785  v_out.get(i, l);
786  lv = rb_int_new(l);
787  rb_ary_store(ret, i+1, lv);
788  }
789  }
790  return ret;
791  }
792  }
793  }
794 bye:
795  return 0;
796 }
797 
798 
799 VALUE TTAudioGetAttributes(VALUE self)
800 {
801  TTAudioInstance* instance = NULL;
802  TTErr err = kTTErrNone;
803  TTValue v;
804  VALUE returnValue = rb_float_new(0.0);
805  TTSymbol s = kTTSymEmpty;
806  TTCString c;
807  TTUInt16 size;
808 
809  err = gTTAudioInstances->lookup(TTPtr(self), v);
810  if (!err) {
811  instance = (TTAudioInstance*)TTPtr(v[0]);
812  if (instance) {
813  TTValue names;
814 
815  instance->parameterNames->getKeys(names);
816  //instance->obj->getAttributeNames(v);
817  //instance->obj->getUnitGenerator()->getAttributeNames(v);
818  size = names.size();
819  returnValue = rb_ary_new2(size);
820  for (TTUInt16 i=0; i<size; i++) {
821  names.get(i, s);
822  c = (TTCString)s.c_str();
823  rb_ary_store(returnValue, i, rb_str_new(c, strlen(c)));
824  }
825  }
826  }
827  return returnValue;
828 }
829 
830 
831 VALUE TTAudioSetAttribute(VALUE self, VALUE attributeName, VALUE attributeValue)
832 {
833  TTAudioInstance* instance = NULL;
834  TTErr err = kTTErrNone;
835  VALUE attributeNameStr = StringValue(attributeName);
836  VALUE attributeValueStr;
837  TTValue v;
838 
839  err = gTTAudioInstances->lookup(TTPtr(self), v);
840  if (!err) {
841  instance = (TTAudioInstance*)TTPtr(v[0]);
842  if (instance) {
843  int t = TYPE(attributeValue);
844 
845  v.clear();
846  //std::cout << "the type of the attr arg is " << t << std::endl;
847  switch (t) {
848  case T_FLOAT:
849  v.append(NUM2DBL(attributeValue));
850  break;
851  case T_FIXNUM:
852  v.append((int)FIX2LONG(attributeValue));
853  break;
854  case T_BIGNUM:
855  v.append((TTInt64)NUM2LL(attributeValue));
856  break;
857  case T_STRING:
858  attributeValueStr = StringValue(attributeValue);
859  v.append(TTSymbol(RSTRING_PTR(attributeValueStr)));
860  break;
861  case T_ARRAY:
862  std::cout << "TTError: Array arguments for attributes not yet supported in Ruby" << std::endl;
863  err = kTTErrGeneric;
864  break;
865  case T_OBJECT:
866  std::cout << "TTError: Object arguments for attributes not yet supported in Ruby" << std::endl;
867  err = kTTErrGeneric;
868  break;
869  default:
870  std::cout << "TTError: Unknown type for arguments to attribute" << std::endl;
871  err = kTTErrGeneric;
872  break;
873  }
874  if (!err) {
875  TTSymbol parameterName = kTTSymEmpty;
876  TTValue parameterNameValue;
877 
878  parameterName = RSTRING_PTR(attributeNameStr);
879  instance->parameterNames->lookup(parameterName, parameterNameValue);
880  parameterNameValue.get(0, parameterName);
881 
882  err = instance->obj.set(parameterName, v);
883  }
884  if (err)
885  std::cout << "TTAudioSetAttribute: Error " << err << std::endl;
886  }
887  }
888  return 0;
889 }
890 
891 
892 VALUE TTAudioGetAttribute(VALUE self, VALUE attributeName)
893 {
894  TTAudioInstance* instance = NULL;
895  TTErr err = kTTErrNone;
896  VALUE attributeNameStr = StringValue(attributeName);
897  //VALUE attributeValueStr;
898  TTValue v;
899  VALUE returnValue = rb_float_new(0.0);
900  TTSymbol s = kTTSymEmpty;
901  TTCString c;
902 
903  err = gTTAudioInstances->lookup(TTPtr(self), v);
904  if (!err) {
905  instance = (TTAudioInstance*)TTPtr(v[0]);
906  if (instance) {
907  TTSymbol parameterName = kTTSymEmpty;
908  TTValue parameterNameValue;
909 
910  parameterName = RSTRING_PTR(attributeNameStr);
911  instance->parameterNames->lookup(parameterName, parameterNameValue);
912  parameterNameValue.get(0, parameterName);
913 
914  err = instance->obj.get(parameterName, v);
915  if (err) {
916  std::cout << "TTAudioGetAttribute: Error " << err << std::endl;
917  goto out;
918  }
919 
920  // TODO: not handling array attrs yet...
921 
922  switch (v[0].type()) {
923  case kTypeFloat64:
924  case kTypeFloat32:
925  returnValue = rb_float_new(v);
926  break;
927  case kTypeInt8:
928  case kTypeUInt8:
929  case kTypeInt16:
930  case kTypeUInt16:
931  case kTypeInt32:
932  case kTypeUInt32:
933  returnValue = INT2NUM(v);
934  break;
935  case kTypeInt64:
936  case kTypeUInt64:
937  returnValue = LL2NUM((TTInt64)v);
938  break;
939  case kTypeBoolean:\
940  returnValue = TTBoolean(v);
941  break;
942  case kTypeSymbol:
943  s = v;
944  c = (TTCString)s.c_str();
945  returnValue = rb_str_new(c, strlen(c));
946  break;
947 
948  case kTypeNone:
949  case kTypeObject:
950  case kTypePointer:
951  case kTypeString:
952  case kTypeLocalValue:
953  case kNumTTDataTypes:
954  default:
955  break;
956  }
957  }
958  }
959 out:
960  return returnValue;
961 }
962 
963 
964 VALUE TTAudioReset(VALUE self)
965 {
966  TTAudioInstance* instance = NULL;
967  TTErr err = kTTErrNone;
968  TTValue v;
969 
970  err = gTTAudioInstances->lookup(TTPtr(self), v);
971  if (!err) {
972  instance = (TTAudioInstance*)TTPtr(v[0]);
973  if (instance) {
974  instance->obj.resetAudio();
975  }
976  }
977  return self;
978 }
979 
980 
981 VALUE TTAudioConnect(int argc, VALUE* argv, VALUE self)
982 {
983  TTAudioInstance* instance = NULL;
984  TTAudioInstance* instanceToConnect = NULL;
985  TTErr err = kTTErrNone;
986  TTValue v;
987  TTUInt16 inletNumberToWhichToConnect = 0;
988  TTUInt16 outletNumberFromWhichToConnect = 0;
989 
990  if (argc < 1) {
991  std::cout << "ERROR -- TTAudioConnect requires at least 1 argument (the object whose output should be connected to our input)" << std::endl;
992  goto bye;
993  }
994 
995  if (TYPE(argv[0]) == T_OBJECT) {
996  err = gTTAudioInstances->lookup(TTPtr(argv[0]), v);
997  if (!err) {
998  instanceToConnect = (TTAudioInstance*)TTPtr(v[0]);
999  }
1000  }
1001 
1002  if (!instanceToConnect) {
1003  std::cout << "ERROR -- TTAudioConnect cannot verify the object you would like to connect" << std::endl;
1004  goto bye;
1005  }
1006 
1007  if (argc > 1) {
1008  inletNumberToWhichToConnect = FIX2LONG(argv[1]);
1009  if (argc > 2)
1010  outletNumberFromWhichToConnect = FIX2LONG(argv[2]);
1011  }
1012 
1013  err = gTTAudioInstances->lookup(TTPtr(self), v);
1014  if (!err) {
1015  instance = (TTAudioInstance*)TTPtr(v[0]);
1016  if (instance) {
1017  instance->obj.connectAudio(instanceToConnect->obj, outletNumberFromWhichToConnect, inletNumberToWhichToConnect);
1018  }
1019  }
1020 bye:
1021  return self;
1022 }
1023 
1024 
1025 VALUE TTAudioDrop(int argc, VALUE* argv, VALUE self)
1026 {
1027  TTAudioInstance* instance = NULL;
1028  TTAudioInstance* instanceToConnect = NULL;
1029  TTErr err = kTTErrNone;
1030  TTValue v;
1031  TTUInt16 inletNumberToWhichToConnect = 0;
1032  TTUInt16 outletNumberFromWhichToConnect = 0;
1033 
1034  if (argc < 1) {
1035  std::cout << "ERROR -- TTAudioConnect requires at least 1 argument (the object whose output should be connected to our input)" << std::endl;
1036  goto bye;
1037  }
1038 
1039  if (TYPE(argv[0]) == T_OBJECT) {
1040  err = gTTAudioInstances->lookup(TTPtr(argv[0]), v);
1041  if (!err) {
1042  instanceToConnect = (TTAudioInstance*)TTPtr(v[0]);
1043  }
1044  }
1045 
1046  if (!instanceToConnect) {
1047  std::cout << "ERROR -- TTAudioConnect cannot verify the object you would like to connect" << std::endl;
1048  goto bye;
1049  }
1050 
1051  if (argc > 1) {
1052  inletNumberToWhichToConnect = FIX2LONG(argv[1]);
1053  if (argc > 2)
1054  outletNumberFromWhichToConnect = FIX2LONG(argv[2]);
1055  }
1056 
1057  err = gTTAudioInstances->lookup(TTPtr(self), v);
1058  if (!err) {
1059  instance = (TTAudioInstance*)TTPtr(v[0]);
1060  if (instance) {
1061  instance->obj.dropAudio(instanceToConnect->obj, outletNumberFromWhichToConnect, inletNumberToWhichToConnect);
1062  }
1063  }
1064 bye:
1065  return self;
1066 }
1067 
1068 
1069 VALUE TTAudioExportMax(VALUE self, VALUE pathToExportFile)
1070 {
1071  TTAudioInstance* instance = NULL;
1072  TTErr err = kTTErrNone;
1073  TTValue v;
1075  VALUE pathToExportStr = StringValue(pathToExportFile);
1076  TTString path = RSTRING_PTR(pathToExportStr);
1077 
1078  err = gTTAudioInstances->lookup(TTPtr(self), v);
1079  if (!err) {
1080  instance = (TTAudioInstance*)TTPtr(v[0]);
1081  if (instance) {
1082  instance->obj.getAudioDescription(desc);
1083  desc.exportMax(path);
1084  }
1085  }
1086  return self;
1087 }
1088 
1089 VALUE TTAudioExportCpp(VALUE self, VALUE pathToExportFile)
1090 {
1091  TTAudioInstance* instance = NULL;
1092  TTErr err = kTTErrNone;
1093  TTValue v;
1095  VALUE pathToExportStr = StringValue(pathToExportFile);
1096  TTString path = RSTRING_PTR(pathToExportStr);
1097 
1098  err = gTTAudioInstances->lookup(TTPtr(self), v);
1099  if (!err) {
1100  instance = (TTAudioInstance*)TTPtr(v[0]);
1101  if (instance) {
1102  instance->obj.getAudioDescription(desc);
1103  desc.exportCpp(path);
1104  }
1105  }
1106  return self;
1107 }
1108 
bool TTBoolean
Boolean flag, same as Boolean on the Mac.
Definition: TTBase.h:167
std::uint16_t TTUInt16
16 bit unsigned integer
Definition: TTBase.h:176
TTErr lookup(const TTSymbol key, TTValue &value)
Find the value for the given key.
Definition: TTHash.cpp:76
Provides all necessary definitions for AudioGraph API.
8-bit unsigned integer, range is 0 through 255.
Definition: TTBase.h:274
const char * c_str() const
Return a pointer to the internal C-string.
Definition: TTString.h:83
Object type.
Definition: TTBase.h:283
64-bit unsigned integer, range is 0 through 18,446,744,073,709,551,615.
Definition: TTBase.h:280
size_type size() const noexcept
Return the number of elements.
This object provides a description of a TTAudioGraphObject and its sources.
Wrap audio objects for convenience.
Maintain a collection of TTValue objects indexed by TTSymbol pointers.
Definition: TTHash.h:36
Symbol type.
Definition: TTBase.h:282
double TTFloat64
64 bit floating point number
Definition: TTBase.h:188
This is a special type used by TTAttribute to indicate that a value is a TTValue and is locally maint...
Definition: TTBase.h:286
16-bit unsigned integer, range is 0 through 65,535.
Definition: TTBase.h:276
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
std::int64_t TTInt64
64 bit signed integer
Definition: TTBase.h:179
16-bit signed integer, range is −32,768 through 32,767.
Definition: TTBase.h:275
64-bit floating point
Definition: TTBase.h:272
The TTSymbol class is used to represent a string and efficiently pass and compare that string...
Definition: TTSymbol.h:26
TTErr append(const TTSymbol key, const TTValue &value)
Insert an item into the hash table.
Definition: TTHash.cpp:70
void get(const TTUInt16 index, T &returnedElementValue) const
DEPRECATED.
Definition: TTValue.h:591
Boolean (1/0) or (true/false) flag.
Definition: TTBase.h:281
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
64-bit signed integer, ragne is −9,223,372,036,854,775,808 through 9,223,372,036,854,775,807
Definition: TTBase.h:279
32-bit floating point
Definition: TTBase.h:271
void clear()
Clear all values from the vector, leaving with size of 0.
Definition: TTValue.h:131
void set(const TTUInt16 index, const T &anElementValue)
DEPRECATED.
Definition: TTValue.h:569
32-bit signed integer, range is -2,147,483,648 through 2,147,483,647.
Definition: TTBase.h:277
Something went wrong, but what exactly is not known. Typically used for context-specific problems...
Definition: TTBase.h:344
TTErr
Jamoma Error Codes Enumeration of error codes that might be returned by any of the TTBlue functions a...
Definition: TTBase.h:342
Pointer type.
Definition: TTBase.h:284
32-bit unsigned integer, range is 0 through 4,294,967,295.
Definition: TTBase.h:278
8-bit signed integer, range is -128 through 127.
Definition: TTBase.h:273
No Error.
Definition: TTBase.h:343
The TTString class is used to represent a string.
Definition: TTString.h:34
String type.
Definition: TTBase.h:285
void resize(size_type n)
Change the number of elements.
[doxygenAppendixC_copyExample]
Definition: TTValue.h:34