Jamoma API  0.6.0.a19
unpack.cpp
1 /*
2  * out≈
3  * External object for Pd to output TTAudioSignals from a Jamoma AudioGraph dsp chain.
4  * Copyright © 2010 by Timothy Place
5  *
6  * License: This code is licensed under the terms of the "New BSD License"
7  * http://creativecommons.org/licenses/BSD/
8  */
9 
10 #include "PureAudioGraph.h"
11 
12 
13 // Data Structure for this object
14 struct Out {
15  Object obj;
16  t_float f; // dummy for signal in first inlet
17  TTAudioGraphObjectPtr audioGraphObject;
18  TTAudioSignalPtr audioSignal;
19  TTUInt16 maxNumChannels; // the number of inlets or outlets, which is an argument at instantiation
20  TTUInt16 numChannels; // the actual number of channels to use, set by the dsp method
21  TTUInt16 vectorSize; // cached by the DSP method
22  TTFloat32 gain; // gain multiplier
23  TTAudioGraphPreprocessData initData; // for the preprocess method
24  t_canvas* canvas;
25 };
26 typedef Out* OutPtr;
27 
28 
29 // Prototypes for methods
30 extern "C" void setup_jcom_unpack0x3d(void);
31 OutPtr OutNew(SymbolPtr msg, AtomCount argc, AtomPtr argv);
32 void OutFree(OutPtr self);
33 TTErr OutReset(OutPtr self, long vectorSize);
34 TTErr OutConnect(OutPtr self, TTAudioGraphObjectPtr audioSourceObject, long sourceOutletNumber);
35 t_int* OutPerform(t_int* w);
36 void OutDsp(OutPtr self, t_signal** sp, short* count);
37 void OutSetGain(OutPtr self, t_floatarg value);
38 
39 
40 // Globals
41 static ClassPtr sOutClass;
42 
43 
44 /************************************************************************************/
45 // Main() Function
46 
47 void setup_jcom_unpack0x3d(void)
48 {
49  TTAudioGraphInit();
50 
51  sOutClass = class_new(gensym("jcom_unpack="), (t_newmethod)OutNew, (t_method)OutFree, sizeof(Out), 0, A_GIMME, 0);
52 
53  CLASS_MAINSIGNALIN(sOutClass, Out, f);
54  class_addmethod(sOutClass, (t_method)OutReset, gensym("audio.reset"), A_CANT, 0);
55  class_addmethod(sOutClass, (t_method)OutConnect, gensym("audio.connect"), A_POINTER, A_POINTER, 0);
56  class_addmethod(sOutClass, (t_method)OutDsp, gensym("dsp"), A_CANT, 0);
57  class_addmethod(sOutClass, (t_method)OutSetGain, gensym("gain"), A_FLOAT, 0);
58 
59  class_sethelpsymbol(sOutClass, gensym("help-jcom_unpack=.pd"));
60 }
61 
62 
63 /************************************************************************************/
64 // Object Creation Method
65 
66 OutPtr OutNew(SymbolPtr msg, AtomCount argc, AtomPtr argv)
67 {
68  OutPtr self;
69  TTValue sr(sys_getsr());
70  short i;
71  TTValue v;
72  TTErr err;
73 
74  self = OutPtr(pd_new(sOutClass));
75  if (self) {
76  self->maxNumChannels = 2; // An initial argument to this object will set the maximum number of channels
77  if(argc && argv)
78  self->maxNumChannels = atom_getfloat(argv)+0.1;
79 
80  ttEnvironment->setAttributeValue(kTTSym_SampleRate, sr);
81 
82  v.setSize(2);
83  v.set(0, TT("gain"));
84  v.set(1, 1); // arg is the number of inlets
85  err = TTObjectInstantiate(TT("audio.object"), (TTObjectPtr*)&self->audioGraphObject, v);
86  self->audioGraphObject->getUnitGenerator()->setAttributeValue(TT("LinearGain"), 1.0);
87 
88  for(i=0; i < self->maxNumChannels; i++)
89  outlet_new(SELF, gensym("signal"));
90 
91  //self->obj.z_misc = Z_NO_INPLACE | Z_PUT_LAST;
92 
93  self->canvas = canvas_getcurrent();
94  }
95  return self;
96 }
97 
98 // Memory Deallocation
99 void OutFree(OutPtr self)
100 {
101  TTObjectRelease((TTObjectPtr*)&self->audioGraphObject);
102 }
103 
104 
105 /************************************************************************************/
106 // Methods bound to input/inlets
107 
108 TTErr OutReset(OutPtr self, long vectorSize)
109 {
110  return self->audioGraphObject->resetAudio();
111 }
112 
113 
114 TTErr OutConnect(OutPtr self, TTAudioGraphObjectPtr audioSourceObject, long sourceOutletNumber)
115 {
116  return self->audioGraphObject->connectAudio(audioSourceObject, sourceOutletNumber);
117 }
118 
119 
120 // Perform (signal) Method
121 t_int* OutPerform(t_int* w)
122 {
123  OutPtr self = (OutPtr)(w[1]);
124  TTUInt16 numChannels;
125 
126  self->audioGraphObject->lockProcessing();
127  self->audioGraphObject->preprocess(self->initData);
128  self->audioGraphObject->process(self->audioSignal);
129  self->audioGraphObject->unlockProcessing();
130 
131  numChannels = TTClip<TTUInt16>(self->numChannels, 0, self->audioSignal->getNumChannelsAsInt());
132  for(TTUInt16 channel=0; channel<numChannels; channel++)
133  self->audioSignal->getVector(channel, self->vectorSize, (TTFloat32*)w[channel+2]);
134  return w + (self->numChannels+2);
135 }
136 
137 
138 // DSP Method
139 void OutDsp(OutPtr self, t_signal** sp, short* count)
140 {
141  TTUInt16 i;
142  TTUInt16 k=0;
143  void **audioVectors = NULL;
144  ObjectPtr o = NULL;
145  t_gotfn audioSetupMethod = NULL;
146  t_gobj *y;
147 
148  self->vectorSize = sp[0]->s_n;
149 
150  /* We need to figure out what objects are connected to what inlets to build the graph:
151 
152  1. Broadcast 'audio.reset' to every object in the patcher, to remove all existing connections.
153  2. Broadcast 'audio.setup' to every object in the patcher, to tell objects to then send
154  'audio.connect' messages to any objects below them.
155  3. When an object received 'audio.connect', then it makes the connection.
156 
157  4. Crawl the graph from bottom to top, call the audio graph init method
158 
159  At this point, the graph is configured and we just need to execute it.
160  We execute the graph from our perform method, which MSP calls once per signal vector.
161 
162  5. Crawl the graph from bottom to top, calling the audio graph preprocess method (prepare for process)
163  6. Crawl the graph from bottom to top, calling the audio graph process method (calculate the samples)
164  7. (Maybe) crawl the graph from bottom to top, calling a audio graph postprocess method
165 
166  For steps 1 & 2, we have to traverse thge patcher twice,
167  because we have to clear all connections first, then add connections.
168  It won't work to do them both during the same traversal because situations arise
169  Where we setup the chain and then it gets reset again by another object
170  (since the order in which we traverse objects is undefined).
171  */
172 
173  // traversal code lifted from line 1105+ in g_canvas.c from Pd
174  // thanks to IOhannes Zmoelnig for the reference to that code...
175 
176  struct _glist_hack
177  {
178  t_object gl_obj; // header in case we're a glist
179  t_gobj *gl_list; // the actual data
180  struct _gstub *gl_stub; // safe pointer handler
181  int gl_valid; // incremented when pointers might be stale
182  struct _glist *gl_owner; // parent glist, supercanvas, or 0 if none
183  };
184 
185  y = ((_glist_hack*)self->canvas)->gl_list;
186  while (y) {
187  o = pd_checkobject(&y->g_pd);
188  if (o) {
189  audioSetupMethod = zgetfn(&y->g_pd, gensym("audio.reset"));
190  if (audioSetupMethod) {
191  audioSetupMethod(o, self->vectorSize);
192  }
193  }
194  y = y->g_next;
195  }
196 
197  y = ((_glist_hack*)self->canvas)->gl_list;
198  while (y) {
199  o = pd_checkobject(&y->g_pd);
200  if (o) {
201  audioSetupMethod = zgetfn(&y->g_pd, gensym("audio.setup"));
202  if (audioSetupMethod)
203  audioSetupMethod(o);
204  }
205  y = y->g_next;
206  }
207 
208  // Setup the perform method
209  audioVectors = (void**)malloc(sizeof(void*) * (self->maxNumChannels + 1));
210  audioVectors[k] = self;
211  k++;
212 
213  self->numChannels = 0;
214  for (i=1; i <= self->maxNumChannels; i++) {
215  self->numChannels++;
216  audioVectors[k] = sp[i]->s_vec;
217  k++;
218  }
219 
220  self->audioGraphObject->getUnitGenerator()->setAttributeValue(TT("SampleRate"), sp[0]->s_sr);
221 
222  dsp_addv(OutPerform, k, (t_int*)audioVectors);
223  free(audioVectors);
224 
225  self->initData.vectorSize = self->vectorSize;
226 }
227 
228 
229 void OutSetGain(OutPtr self, t_floatarg value)
230 {
231  self->gain = value;
232  self->audioGraphObject->getUnitGenerator()->setAttributeValue(TT("LinearGain"), self->gain);
233 }
234 
std::uint16_t TTUInt16
16 bit unsigned integer
Definition: TTBase.h:176
TTFOUNDATION_EXPORT TTEnvironment * ttEnvironment
The environment object has one instance, which is global in scope.
TTErr setAttributeValue(const TTSymbol name, TTValue &value)
Set an attribute value for an object.
#define TT
This macro is defined as a shortcut for doing a lookup in the symbol table.
Definition: TTSymbol.h:155
void setSize(const TTUInt16 arg)
DEPRECATED.
Definition: TTValue.h:528
float TTFloat32
32 bit floating point number
Definition: TTBase.h:187
The TTAudioSignal class represents N vectors of audio samples for M channels.
Definition: TTAudioSignal.h:57
void set(const TTUInt16 index, const T &anElementValue)
DEPRECATED.
Definition: TTValue.h:569
TTErr
Jamoma Error Codes Enumeration of error codes that might be returned by any of the TTBlue functions a...
Definition: TTBase.h:342
[doxygenAppendixC_bitmaskExample]
Definition: TTAudioGraph.h:81
[doxygenAppendixC_copyExample]
Definition: TTValue.h:34