Jamoma API  0.6.0.a19
allpass1~.model.cpp
Go to the documentation of this file.
1 /** @file
2  * @ingroup implementationMaxModels
3  *
4  * @brief allpass~.model: Wraps the #TTAllpass1 class as a Jamoma model in the form of a C++ external
5  *
6  * @details
7  *
8  * @authors Tim Place, Trond Lossius
9  *
10  * @copyright Copyright © 2013, Tim Place @n
11  * This code is licensed under the terms of the "New BSD License" @n
12  * http://creativecommons.org/licenses/BSD/
13  */
14 
15 
17 #include "ext.h" // Max Header
18 #include "z_dsp.h" // MSP Header
19 #include "ext_obex.h" // Max Object Extensions (attributes) Header
20 
21 
22 // Data Structure for this object
23 typedef struct _allpassmod {
24  t_pxobject obj;
25 
26  TTObject model;
27 
28  TTObject parameter_coefficient;
29  TTObject parameter_delay;
30  TTObject message_clear;
31 
32  TTObject in_left;
33  TTObject in_right;
34  TTObject out_left;
35  TTObject out_right;
36  TTObject preset;
37 
38  TTAudioObject allpass;
39  TTObject signalIn;
40  TTObject signalOut;
41 
42  TTAddress name;
43 } t_allpassmod;
44 
45 
46 // Prototypes for methods
47 void* allpassmod_new(t_symbol *s, long argc, t_atom *argv);
48 void allpassmod_free(t_allpassmod *x);
49 void allpassmod_dsp64(t_allpassmod *x, t_object *dsp64, short *count, double samplerate, long maxvectorsize, long flags);
50 void allpassmod_assist(t_allpassmod *x, void *b, long m, long a, char *s);
51 void allpassmod_parameter_coefficient_callback(const TTValue& baton, const TTValue& v);
52 void allpassmod_parameter_delay_callback(const TTValue& baton, const TTValue& v);
53 void allpassmod_parameter_clear_callback(const TTValue& baton, const TTValue& v);
54 
55 
56 // Globals
57 static t_class* s_allpassmod_class;
58 
59 
60 /************************************************************************************/
61 // Define our class
62 
63 int C74_EXPORT main(void)
64 {
65  t_class *c = class_new("allpass1~.model", (method)allpassmod_new, (method)allpassmod_free, sizeof(t_allpassmod), (method)0L, A_GIMME, 0);
66 
67  TTDSPInit();
68 
69  class_addmethod(c, (method)allpassmod_dsp64, "dsp64", A_CANT, 0);
70  class_addmethod(c, (method)object_obex_dumpout, "dumpout", A_CANT,0);
71  class_addmethod(c, (method)allpassmod_assist, "assist", A_CANT, 0L);
72  class_dspinit(c);
73 
74  class_register(CLASS_BOX, c);
75  s_allpassmod_class = c;
76  return 0;
77 }
78 
79 
80 /************************************************************************************/
81 // Object Life
82 
83 // Create
84 void* allpassmod_new(t_symbol* s, long argc, t_atom* argv)
85 {
86  t_allpassmod* x = (t_allpassmod*)object_alloc(s_allpassmod_class);
87  long attrstart = attr_args_offset(argc, argv); // support normal arguments
88  TTString name = "/";
89  TTPtr context = TTPtr(x);
90  TTValue none;
91 
92  object_obex_lookup(x, gensym("#P"), (t_object**)&context);
93 
94  if (attrstart) {
95  if (atom_getsym(argv)->s_name[0] == '/')
96  name += atom_getsym(argv)->s_name + 1;
97  else
98  name += atom_getsym(argv)->s_name;
99  }
100  else
101  name += s->s_name;
102 
103  x->name = TTAddress(name); // need to cache so we can free
104 
105  // 1. Create the DSP objects
106  x->allpass = TTAudioObject("allpass.1", 2);
107  x->signalOut = TTObject(kTTSym_audiosignal, 2);
108  x->signalIn = TTObject(kTTSym_audiosignal, 2);
109 
110  // 2. Create the "model" container
111  {
112  TTValue container_args; // TODO: (optional) pass address callback and value callback (these are both for the activity return mechanism)
113 
114  x->model = TTObject(kTTSym_Container, container_args);
115  x->model.set(kTTSym_tags, kTTSym_model);
116 
117  TTValue registration_args(x->name, x->model, context);
118  JamomaApplication.send("ObjectRegister", registration_args, none);
119 
120  x->model.set("address", x->name);
121  }
122 
123  // 3. Create the "clear" message
124  {
125  x->message_clear = TTObject(kTTSym_Data, kTTSym_message);
126  x->message_clear.set(kTTSym_baton, TTPtr(x));
127  x->message_clear.set(kTTSym_function, TTPtr(allpassmod_parameter_clear_callback));
128  x->message_clear.set(kTTSym_type, kTTSym_none);
129  x->message_clear.set(kTTSym_description, TTSymbol("Clear the filter history"));
130 
131  TTAddress address = x->name.appendAddress("/clear");
132  TTValue registration_args(address, x->message_clear, context);
133  JamomaApplication.send("ObjectRegister", registration_args, none);
134  }
135 
136  // 4. Create the "gain" parameter (linear)
137  {
138  x->parameter_coefficient = TTObject(kTTSym_Data, kTTSym_parameter);
139  x->parameter_coefficient.set(kTTSym_baton, TTPtr(x));
140  x->parameter_coefficient.set(kTTSym_function, TTPtr(allpassmod_parameter_coefficient_callback));
141  x->parameter_coefficient.set(kTTSym_type, kTTSym_decimal);
142  x->parameter_coefficient.set(kTTSym_valueDefault, 0.7);
143  x->parameter_coefficient.set(kTTSym_description, TTSymbol("Gain coefficient"));
144 
145  TTAddress address = x->name.appendAddress("/coefficient");
146  TTValue registration_args(address, x->parameter_coefficient, context);
147  JamomaApplication.send("ObjectRegister", registration_args, none);
148  }
149 
150  // 5. Create the "delay" parameter (milliseconds)
151  {
152  x->parameter_delay = TTObject(kTTSym_Data, kTTSym_parameter);
153  x->parameter_delay.set(kTTSym_baton, TTPtr(x));
154  x->parameter_delay.set(kTTSym_function, TTPtr(allpassmod_parameter_delay_callback));
155  x->parameter_delay.set(kTTSym_type, kTTSym_decimal);
156  x->parameter_delay.set(kTTSym_valueDefault, 0.2);
157  x->parameter_delay.set(kTTSym_description, TTSymbol("Delay time"));
158 
159  TTAddress address = x->name.appendAddress("/delay");
160  TTValue registration_args(address, x->parameter_delay, context);
161  JamomaApplication.send("ObjectRegister", registration_args, none);
162  }
163 
164  // 6. Create the Input access points
165  {
166  // left input
167  {
168  x->in_left = TTObject("Input.audio");
169 
170  TTAddress address = x->name.appendAddress("/in.left");
171  TTValue registration_args(address, x->in_left, context);
172  JamomaApplication.send("ObjectRegister", registration_args, none);
173  }
174 
175  // right input
176  {
177  x->in_right = TTObject("Input.audio");
178 
179  TTAddress address = x->name.appendAddress("/in.right");
180  TTValue registration_args(address, x->in_right, context);
181  JamomaApplication.send("ObjectRegister", registration_args, none);
182  }
183  }
184 
185  // 7. Create the Output access points
186  {
187  // left output
188  {
189  x->out_left = TTObject("Output.audio");
190 
191  TTAddress address = x->name.appendAddress("/out.left");
192  TTValue registration_args(address, x->out_left, context);
193  JamomaApplication.send("ObjectRegister", registration_args, none);
194  }
195 
196  // right output
197  {
198  x->out_right = TTObject("Output.audio");
199 
200  TTAddress address = x->name.appendAddress("/out.right");
201  TTValue registration_args(address, x->out_right, context);
202  JamomaApplication.send("ObjectRegister", registration_args, none);
203  }
204  }
205 
206  // 8. Add the preset functions
207  {
208  x->preset = TTObject(kTTSym_PresetManager);
209  x->preset.set("address", x->name);
210 
211  TTAddress address = x->name.appendAddress("/preset");
212  TTValue registration_args(address, x->preset, context);
213  JamomaApplication.send("ObjectRegister", registration_args, none);
214 
215  // load a preset file and recall the first preset
216  {
217  TTValue out;
218  TTObject xmlHandler("XmlHandler");
219 
220  // set the object attr of the above object to be the PresetManager
221  xmlHandler.set("object", x->preset);
222 
223  // TODO : get the filepath as an argument
224  TTSymbol path;
225  xmlHandler.send("Read", path, out);
226 
227  // recall the first preset
228  x->preset.send("Recall", 1, none);
229  }
230  }
231 
232  // 9. Initialize the module (set default values, etc)
233  x->model.send("Init");
234 
235  // 10. Do some final Max-specific stuff
236  dsp_setup((t_pxobject*)x, 2);
237  x->obj.z_misc = Z_NO_INPLACE;
238  for (int i=0; i < 2; i++)
239  outlet_new((t_pxobject*)x, "signal");
240 
241  attr_args_process(x, argc, argv);
242  return x;
243 }
244 
245 // Destroy
246 void allpassmod_free(t_allpassmod *x)
247 {
248  dsp_free((t_pxobject *)x);
249 
250  TTValue none;
251  TTAddress address;
252 
253  address = x->name.appendAddress("/model");
254  JamomaApplication.send("ObjectUnregister", address, none);
255 
256  address = x->name.appendAddress("/coefficient");
257  JamomaApplication.send("ObjectUnregister", address, none);
258 
259  address = x->name.appendAddress("/delay");
260  JamomaApplication.send("ObjectUnregister", address, none);
261 
262  address = x->name.appendAddress("/clear");
263  JamomaApplication.send("ObjectUnregister", address, none);
264 
265  address = x->name.appendAddress("/in.left");
266  JamomaApplication.send("ObjectUnregister", address, none);
267 
268  address = x->name.appendAddress("/in.right");
269  JamomaApplication.send("ObjectUnregister", address, none);
270 
271  address = x->name.appendAddress("/out.left");
272  JamomaApplication.send("ObjectUnregister", address, none);
273 
274  address = x->name.appendAddress("/out.right");
275  JamomaApplication.send("ObjectUnregister", address, none);
276 
277  address = x->name.appendAddress("/preset");
278  JamomaApplication.send("ObjectUnregister", address, none);
279 }
280 
281 
282 /************************************************************************************/
283 
284 void allpassmod_assist(t_allpassmod *x, void *b, long msg, long arg, char *dst)
285 {
286 }
287 
288 
289 // Callback we receive when the parameter value changes
290 void allpassmod_parameter_coefficient_callback(const TTValue& baton, const TTValue& v)
291 {
292  t_allpassmod *x = (t_allpassmod*)TTPtr(baton[0]);
293  x->allpass.set("linearGain", v);
294 }
295 
296 
297 // Callback we receive when the parameter value changes
298 void allpassmod_parameter_delay_callback(const TTValue& baton, const TTValue& v)
299 {
300  t_allpassmod *x = (t_allpassmod*)TTPtr(baton[0]);
301  x->allpass.set("delay", v);
302 }
303 
304 
305 void allpassmod_parameter_clear_callback(const TTValue& baton, const TTValue& v)
306 {
307  t_allpassmod *x = (t_allpassmod*)TTPtr(baton[0]);
308  x->allpass.send("clear");
309 }
310 
311 
312 void allpassmod_perform64(t_allpassmod *x, t_object *dsp64, double **ins, long numins, double **outs, long numouts, long sampleframes, long flags, void *userparam)
313 {
314  // cast objects
315  TTInputAudioPtr in_left_instance = TTInputAudioPtr(x->in_left.instance());
316  TTInputAudioPtr in_right_instance = TTInputAudioPtr(x->in_right.instance());
317  TTAudioObjectBasePtr allpass_instance = TTAudioObjectBasePtr(x->allpass.instance());
318  TTAudioSignalPtr signalIn_instance = TTAudioSignalPtr(x->signalIn.instance());
319  TTAudioSignalPtr signalOut_instance = TTAudioSignalPtr(x->signalOut.instance());
320  TTOutputAudioPtr out_left_instance = TTOutputAudioPtr(x->out_left.instance());
321  TTOutputAudioPtr out_right_instance = TTOutputAudioPtr(x->out_right.instance());
322 
323  in_left_instance->process(ins[0], NULL, sampleframes);
324  in_right_instance->process(ins[1], NULL, sampleframes);
325 
326  // need to compile a stereo signal out of the multiple mono signals
327  signalIn_instance->setVector(0, sampleframes, in_left_instance->getVector());
328  signalIn_instance->setVector(1, sampleframes, in_right_instance->getVector());
329 
330  // actually process the audio
331  allpass_instance->process(signalIn_instance, signalOut_instance);
332 
333  // we re-use the memory from ins[], which is safe because we set Z_NO_INPLACE in the object constructor
334  signalOut_instance->getVectorCopy(0, sampleframes, ins[0]);
335  signalOut_instance->getVectorCopy(1, sampleframes, ins[1]);
336 
337  out_left_instance->process(ins[0], outs[0], sampleframes);
338  out_right_instance->process(ins[1], outs[1], sampleframes);
339 }
340 
341 
342 void allpassmod_dsp64(t_allpassmod *x, t_object *dsp64, short *count, double samplerate, long maxvectorsize, long flags)
343 {
344  // cast objects
345  TTInputAudioPtr in_left_instance = TTInputAudioPtr(x->in_left.instance());
346  TTInputAudioPtr in_right_instance = TTInputAudioPtr(x->in_right.instance());
347  TTAudioObjectBasePtr allpass_instance = TTAudioObjectBasePtr(x->allpass.instance());
348  TTAudioSignalPtr signalIn_instance = TTAudioSignalPtr(x->signalIn.instance());
349  TTAudioSignalPtr signalOut_instance = TTAudioSignalPtr(x->signalOut.instance());
350  TTOutputAudioPtr out_left_instance = TTOutputAudioPtr(x->out_left.instance());
351  TTOutputAudioPtr out_right_instance = TTOutputAudioPtr(x->out_right.instance());
352 
353  signalIn_instance->setNumChannels(2);
354  signalOut_instance->setNumChannels(2);
355 
356  signalIn_instance->setVectorSizeWithInt((TTUInt16)maxvectorsize);
357  signalOut_instance->setVectorSizeWithInt((TTUInt16)maxvectorsize);
358 
359  signalOut_instance->alloc();
360 
361  allpass_instance->setAttributeValue(kTTSym_sampleRate, samplerate);
362  object_method(dsp64, gensym("dsp_add64"), x, allpassmod_perform64, 0, NULL);
363 
364  in_left_instance->setupAudioSignals(maxvectorsize);
365  in_right_instance->setupAudioSignals(maxvectorsize);
366  out_left_instance->setupAudioSignals(maxvectorsize, samplerate);
367  out_right_instance->setupAudioSignals(maxvectorsize, samplerate);
368 }
TTAddress appendAddress(const TTAddress &toAppend)
Return a new TTAddress with the appended part.
Definition: TTAddress.h:167
std::uint16_t TTUInt16
16 bit unsigned integer
Definition: TTBase.h:176
TTErr send(const TTSymbol aName)
Send a message to this object with no arguments.
Definition: TTObject.cpp:135
void process(TTSampleValue *anInputSampleVector, TTSampleValue *anOutputSampleVector, TTUInt16 aVectorSize)
Called by the perform method in j.in~ to pass the samples in from the outside world Will also be call...
TTSampleValue * getVector()
Used in e.g.
Definition: TTInputAudio.h:39
TTAudioObjectBase is the base class for all audio generating and processing objects in Jamoma DSP...
The TTAddress class is used to represent a string and efficiently pass and compare that string...
Definition: TTAddress.h:29
Create and use Jamoma object instances.
Definition: TTObject.h:29
Wrap audio objects for convenience.
TTErr setAttributeValue(const TTSymbol name, TTValue &value)
Set an attribute value for an object.
void * TTPtr
A generic pointer.
Definition: TTBase.h:248
TTAudioObjectBase * TTAudioObjectBasePtr
Pointer to a TTAudioObjectBase.
The TTSymbol class is used to represent a string and efficiently pass and compare that string...
Definition: TTSymbol.h:26
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
int C74_EXPORT main(void)
Set up this class as a Max external the first time an object of this kind is instantiated.
Wraps Jamoma Core classes as objects for Max/MSP.
void setupAudioSignals(TTUInt16 aVectorSize)
Used e.g.
Definition: TTInputAudio.h:46
The TTString class is used to represent a string.
Definition: TTString.h:34
An audio output component for Jamoma models.
Definition: TTOutputAudio.h:23
[doxygenAppendixC_copyExample]
Definition: TTValue.h:34
An audio input component for Jamoma models.
Definition: TTInputAudio.h:23