Jamoma API  0.6.0.a19
j.balance~.cpp
Go to the documentation of this file.
1 /** @file
2  *
3  * @ingroup implementationMaxExternalsDSP
4  *
5  * @brief j.balance~ : The amplitude envelope of one audio signal imitates that of another
6  *
7  * @details The code is based on an algorithm from Dodge & Jerse (1997): Computer Music: Synthesis, Composition, and Performance.
8  *
9  * @authors Trond Lossius
10  *
11  * @copyright Copyright © 2008 by Trond Lossius @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 "TTClassWrapperMax.h"
18 #include "ext.h" // Max Header
19 #include "z_dsp.h" // MSP Header
20 #include "ext_strings.h" // String Functions
21 #include "commonsyms.h" // Common symbols used by the Max 4.5 API
22 #include "ext_obex.h" // Max Object Extensions (attributes) Header
23 
24 #include "TTDSP.h" // Jamoma DSP Interfaces...
25 
26 
27 // Data Structure for this object
28 typedef struct _balance {
29  t_pxobject obj;
30  TTAudioObjectBasePtr balance;
31  TTAudioSignalPtr audioIn;
32  TTAudioSignalPtr audioOut;
33  long attrBypass;
34  float attrFrequency;
35  TTUInt16 maxNumChannels;
36  TTUInt16 numChannels;
37  TTUInt16 vs;
38 } t_balance;
39 
40 
41 // Prototypes for methods: need a method for each incoming message type
42 void* balance_new(t_symbol *msg, short argc, t_atom *argv); // New Object Creation Method
43 void balance_free(t_balance *x);
44 void balance_assist(t_balance *x, void *b, long msg, long arg, char *dst); // Assistance Method
45 t_int* balance_perform(t_int *w); // An MSP Perform (signal) Method
46 void balance_dsp(t_balance *x, t_signal **sp, short *count); // DSP Method
47 void balance_dsp64(t_balance *x, t_object *dsp64, short *count, double samplerate, long maxvectorsize, long flags); // DSP64 Method
48 void balance_clear(t_balance *x);
49 t_max_err balance_setBypass(t_balance *x, void *attr, long argc, t_atom *argv);
50 t_max_err balance_setFrequency(t_balance *x, void *attr, long argc, t_atom *argv);
51 
52 
53 // Globals
54 t_class *balance_class; // Required. Global pointing to this class
55 
56 
57 /************************************************************************************/
58 // Main() Function
59 
60 int C74_EXPORT main(void)
61 {
62  long attrflags = 0;
63  t_class *c;
64  t_object *attr;
65 
66  TTDSPInit();
67  common_symbols_init();
68 
69  c = class_new("j.balance~",(method)balance_new, (method)balance_free, (short)sizeof(t_balance),
70  (method)0L, A_GIMME, 0);
71 
72  class_addmethod(c, (method)balance_clear, "clear", 0L);
73  class_addmethod(c, (method)balance_dsp, "dsp", A_CANT, 0L);
74  class_addmethod(c, (method)balance_dsp64, "dsp64", A_CANT, 0);
75  class_addmethod(c, (method)balance_assist, "assist", A_CANT, 0L);
76 
77  attr = attr_offset_new("bypass", _sym_long, attrflags,
78  (method)0L,(method)balance_setBypass, calcoffset(t_balance, attrBypass));
79  class_addattr(c, attr);
80 
81  attr = attr_offset_new("frequency", _sym_float32, attrflags,
82  (method)0L,(method)balance_setFrequency, calcoffset(t_balance, attrFrequency));
83  class_addattr(c, attr);
84 
85  class_dspinit(c); // Setup object's class to work with MSP
86  class_register(CLASS_BOX, c);
87  balance_class = c;
88 
89  return 0;
90 }
91 
92 
93 /************************************************************************************/
94 // Object Creation Method
95 
96 void* balance_new(t_symbol *msg, short argc, t_atom *argv)
97 {
98  t_balance *x;
99  TTValue sr(sys_getsr());
100  long attrstart = attr_args_offset(argc, argv); // support normal arguments
101  short i;
102 
103  x = (t_balance *)object_alloc(balance_class);
104  if (x) {
105  // Default values
106  x->attrFrequency = 10;
107  x->attrBypass = 0;
108  // An initial argument to this object will set the maximum number of channels to process
109  // Two input channels are required for each processed channel (source and comperator)
110  x->maxNumChannels = 1;
111  if (attrstart && argv)
112  x->maxNumChannels = atom_getlong(argv);
113 
114  ttEnvironment->setAttributeValue(kTTSym_sampleRate, sr);
115  TTObjectBaseInstantiate(TT("balance"), &x->balance, x->maxNumChannels);
116  TTObjectBaseInstantiate(TT("audiosignal"), &x->audioIn, x->maxNumChannels*2);
117  TTObjectBaseInstantiate(TT("audiosignal"), &x->audioOut, x->maxNumChannels);
118 
119  attr_args_process(x,argc,argv); // handle attribute args
120 
121  object_obex_store((void *)x, _sym_dumpout, (object *)outlet_new(x,NULL)); // dumpout
122  dsp_setup((t_pxobject *)x, x->maxNumChannels*2); // inlets
123  for (i=0; i < x->maxNumChannels; i++)
124  outlet_new((t_pxobject *)x, "signal"); // outlets
125 
126  x->obj.z_misc = Z_NO_INPLACE;
127  }
128  return (x); // Return the pointer
129 }
130 
131 // Memory Deallocation
132 void balance_free(t_balance *x)
133 {
134  dsp_free((t_pxobject *)x);
135  TTObjectBaseRelease(&x->balance);
136  TTObjectBaseRelease(&x->audioIn);
137  TTObjectBaseRelease(&x->audioOut);
138 }
139 
140 
141 /************************************************************************************/
142 // Methods bound to input/inlets
143 
144 // Method for Assistance Messages
145 void balance_assist(t_balance *x, void *b, long msg, long arg, char *dst)
146 {
147  if (msg==1) { // Inlets
148  if (arg == 0)
149  snprintf(dst, 256, "(signal) to balance (ch. %ld), control messages", arg+1);
150  else if (arg < x->maxNumChannels)
151  snprintf(dst, 256, "(signal) to balance (ch. %ld)", arg+1);
152  else if (arg >= x->maxNumChannels)
153  snprintf(dst, 256, "(signal) Comperator (ch. %ld)", arg-x->maxNumChannels+1);
154  }
155  else if (msg==2) {// Outlets
156  if (arg == x->maxNumChannels)
157  strcpy(dst, "dumpout");
158  else
159  snprintf(dst, 256, "(signal) Balanced output %ld", arg+1);
160  }
161 }
162 
163 
164 void balance_clear(t_balance *x)
165 {
166  x->balance->sendMessage(TT("clear"));
167 }
168 
169 
170 // Perform (signal) Method
171 t_int *balance_perform(t_int *w)
172 {
173  t_balance *x = (t_balance *)(w[1]);
174  short i, j, k;
175  TTUInt16 vs = x->audioIn->getVectorSizeAsInt();
176 
177  // We sort audioIn so that all channels of signalA comes first, then all channels of signalB
178  for (i=0; i < x->numChannels; i++) {
179  j = (i*3) + 1;
180  k = i + x->numChannels;
181  x->audioIn->setVector(i, vs, (t_float *)w[j+1]);
182  x->audioIn->setVector(k, vs, (t_float *)w[j+2]);
183  }
184 
185  if (!x->obj.z_disabled) // if we are not muted...
186  x->balance->process(*x->audioIn, *x->audioOut); // Actual balance process
187 
188  for (i=0; i < x->numChannels; i++) {
189  j = (i*3) + 1;
190  x->audioOut->getVector(i, vs, (t_float *)w[j+3]);
191  }
192 
193  return w + ((x->numChannels*3)+2); // +2 = +1 for the x pointer and +1 to point to the next object
194 }
195 
196 
197 // DSP Method: Adds our perform method to the DSP call chain
198 void balance_dsp(t_balance *x, t_signal **sp, short *count)
199 {
200  short i, j, k, l=0;
201  void **audioVectors = NULL;
202 
203  audioVectors = (void**)sysmem_newptr(sizeof(void*) * ((x->maxNumChannels * 3) + 1));
204  audioVectors[l] = x;
205  l++;
206 
207  // audioVectors[] passed to balance_perform() as {x, audioInL[0], audioInR[0], audioOut[0], audioInL[1], audioInR[1], audioOut[1],...}
208  x->numChannels = 0;
209  x->vs = 0;
210  for (i=0; i < x->maxNumChannels; i++) {
211  j = x->maxNumChannels + i;
212  k = x->maxNumChannels*2 + i;
213  if (count[i] && count[j] && count[k]) {
214  x->numChannels++;
215  if (sp[i]->s_n > x->vs)
216  x->vs = sp[i]->s_n;
217 
218  audioVectors[l] = sp[i]->s_vec;
219  l++;
220  audioVectors[l] = sp[j]->s_vec;
221  l++;
222  audioVectors[l] = sp[k]->s_vec;
223  l++;
224  }
225  }
226 
227  x->audioOut->setAttributeValue(kTTSym_numChannels, x->numChannels*2);
228  x->audioOut->setAttributeValue(kTTSym_numChannels, x->numChannels);
229  x->audioIn->setAttributeValue(kTTSym_vectorSize, x->vs);
230  x->audioOut->setAttributeValue(kTTSym_vectorSize, x->vs);
231  //audioIn will be set in the perform method
232  x->audioOut->sendMessage(TT("alloc"));
233 
234  x->balance->setAttributeValue(kTTSym_sampleRate, sp[0]->s_sr);
235 
236  dsp_addv(balance_perform, l, audioVectors);
237  sysmem_freeptr(audioVectors);
238 }
239 
240 
241 t_max_err balance_setBypass(t_balance *x, void *attr, long argc, t_atom *argv)
242 {
243  if (argc) {
244  x->attrBypass = atom_getlong(argv);
245  x->balance->setAttributeValue(kTTSym_bypass, (TTBoolean)x->attrBypass);
246  }
247  return MAX_ERR_NONE;
248 }
249 
250 
251 t_max_err balance_setFrequency(t_balance *x, void *attr, long argc, t_atom *argv)
252 {
253  if (argc) {
254  x->attrFrequency = atom_getfloat(argv);
255  x->balance->setAttributeValue(TT("frequency"), x->attrFrequency);
256  }
257  return MAX_ERR_NONE;
258 }
259 
260 
261 void balance_perform64(t_balance *x, t_object *dsp64, double **ins, long numins, double **outs, long numouts, long sampleframes, long flags, void *userparam)
262 {
263 
264  short i;
265  TTUInt16 vs = x->audioIn->getVectorSizeAsInt();
266 
267  // We sort audioIn so that all channels of signalA comes first, then all channels of signalB
268  for (i=0; i < numouts; i++) {
269  x->audioIn->setVector(i, vs, ins[i]);
270  x->audioIn->setVector(i+numouts, vs, ins[i+numouts]);
271  }
272 
273  x->balance->process(*x->audioIn, *x->audioOut); // Actual balance process
274 
275  for (i=0; i < x->numChannels; i++)
276  x->audioOut->getVectorCopy(i, vs, outs[i]);
277 
278 
279 }
280 
281 
282 
283 void balance_dsp64(t_balance *x, t_object *dsp64, short *count, double samplerate, long maxvectorsize, long flags)
284 {
285  short i, j, k;
286 
287  x->numChannels = 0;
288  x->vs = maxvectorsize;
289  for (i=0; i < x->maxNumChannels; i++) {
290  j = x->maxNumChannels + i;
291  k = x->maxNumChannels*2 + i;
292  if (count[i] && count[j] && count[k])
293  x->numChannels++;
294  }
295 
296  x->audioOut->setAttributeValue(kTTSym_numChannels, x->numChannels*2);
297  x->audioOut->setAttributeValue(kTTSym_numChannels, x->numChannels);
298  x->audioIn->setAttributeValue(kTTSym_vectorSize, (TTUInt16)maxvectorsize);
299  x->audioOut->setAttributeValue(kTTSym_vectorSize, (TTUInt16)maxvectorsize);
300  //audioIn will be set in the perform method
301  x->audioOut->sendMessage(TT("alloc"));
302 
303  x->balance->setAttributeValue(kTTSym_sampleRate, samplerate);
304  object_method(dsp64, gensym("dsp_add64"), x, balance_perform64, 0, NULL);
305 
306 
307 }
308 
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 TTObjectBaseRelease(TTObjectBasePtr *anObject)
DEPRECATED.
TTFOUNDATION_EXPORT TTEnvironment * ttEnvironment
The environment object has one instance, which is global in scope.
TTAudioObjectBase is the base class for all audio generating and processing objects in Jamoma DSP...
Jamoma DSP Library.
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
int C74_EXPORT main(void)
Set up this class as a Max external the first time an object of this kind is instantiated.
Definition: j.balance~.cpp:60
TTErr TTObjectBaseInstantiate(const TTSymbol className, TTObjectBasePtr *returnedObjectPtr, const TTValue arguments)
DEPRECATED.
The TTAudioSignal class represents N vectors of audio samples for M channels.
Definition: TTAudioSignal.h:57
void TTDSP_EXPORT TTDSPInit(const char *pathToBinaries=NULL)
Initialise the Jamoma DSP library, as well as Jamoma Foundation foundation if needed.
Definition: TTDSP.cpp:30
[doxygenAppendixC_copyExample]
Definition: TTValue.h:34