Jamoma API  0.6.0.a19
CAAUMIDIMap.h
1 /* Copyright © 2007 Apple Inc. All Rights Reserved.
2 
3  Disclaimer: IMPORTANT: This Apple software is supplied to you by
4  Apple Inc. ("Apple") in consideration of your agreement to the
5  following terms, and your use, installation, modification or
6  redistribution of this Apple software constitutes acceptance of these
7  terms. If you do not agree with these terms, please do not use,
8  install, modify or redistribute this Apple software.
9 
10  In consideration of your agreement to abide by the following terms, and
11  subject to these terms, Apple grants you a personal, non-exclusive
12  license, under Apple's copyrights in this original Apple software (the
13  "Apple Software"), to use, reproduce, modify and redistribute the Apple
14  Software, with or without modifications, in source and/or binary forms;
15  provided that if you redistribute the Apple Software in its entirety and
16  without modifications, you must retain this notice and the following
17  text and disclaimers in all such redistributions of the Apple Software.
18  Neither the name, trademarks, service marks or logos of Apple Inc.
19  may be used to endorse or promote products derived from the Apple
20  Software without specific prior written permission from Apple. Except
21  as expressly stated in this notice, no other rights or licenses, express
22  or implied, are granted by Apple herein, including but not limited to
23  any patent rights that may be infringed by your derivative works or by
24  other works in which the Apple Software may be incorporated.
25 
26  The Apple Software is provided by Apple on an "AS IS" basis. APPLE
27  MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
28  THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
29  FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
30  OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
31 
32  IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
33  OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35  INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
36  MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
37  AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
38  STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
39  POSSIBILITY OF SUCH DAMAGE.
40 */
41 #ifndef __CAAUMIDIMap_h_
42 #define __CAAUMIDIMap_h_
43 
44 #include <AudioUnit/AudioUnitProperties.h>
45 #include <algorithm>
46 
47 /*
48 enum {
49  kAUParameterMIDIMapping_AnyChannelFlag = (1L << 0),
50  // If this flag is set and mStatus is a MIDI channel message, then the MIDI channel number
51  // in the status byte is ignored; the mapping is from the specified MIDI message on ANY channel.
52 
53  kAUParameterMIDIMapping_AnyNoteFlag = (1L << 1),
54  // If this flag is set and mStatus is a Note On, Note Off, or Polyphonic Pressure message,
55  // the message's note number is ignored; the mapping is from ANY note number.
56 
57  kAUParameterMIDIMapping_SubRange = (1L << 2),
58  // set this flag if the midi control should map only to a sub-range of the parameter's value
59  // then specify that range in the mSubRangeMin and mSubRangeMax members
60 
61  kAUParameterMIDIMapping_Toggle = (1L << 3),
62  // this is only useful for boolean typed parameters. When set, it means that the parameter's
63  // value should be toggled (if true, become false and vice versa) when the represented MIDI message
64  // is received
65 
66  kAUParameterMIDIMapping_Bipolar = (1L << 4),
67  // this can be set to when mapping a MIDI Controller to indicate that the parameter (typically a boolean
68  // style parameter) will only have its value changed to either the on or off state of a MIDI controller message
69  // (0 < 64 is off, 64 < 127 is on) such as the sustain pedal. The seeting of the next flag
70  // (kAUParameterMIDIMapping_Bipolar_On) determine whether the parameter is mapped to the on or off
71  // state of the controller
72  kAUParameterMIDIMapping_Bipolar_On = (1L << 5)
73  // only a valid flag if kAUParameterMIDIMapping_Bipolar is set
74 };
75 
76 // The reserved fields here are being used to reserve space (as well as align to 64 bit size) for future use
77 // When/If these fields are used, the names of the fields will be changed to reflect their functionality
78 // so, apps should NOT refer to these reserved fields directly by name
79 typedef struct AUParameterMIDIMapping
80 {
81  AudioUnitScope mScope;
82  AudioUnitElement mElement;
83  AudioUnitParameterID mParameterID;
84  UInt32 mFlags;
85  Float32 mSubRangeMin;
86  Float32 mSubRangeMax;
87  UInt8 mStatus;
88  UInt8 mData1;
89  UInt8 reserved1; // MUST be set to zero
90  UInt8 reserved2; // MUST be set to zero
91  UInt32 reserved3; // MUST be set to zero
92 } AUParameterMIDIMapping;
93 */
94 
95 /*
96 Parameter To MIDI Mapping Properties
97 These properties are used to:
98 Describe a current set of mappings between MIDI messages and Parameter value setting
99 Create a mapping between a parameter and a MIDI message through either:
100 - explicitly adding (or removing) the mapping
101 - telling the AU to hot-map the next MIDI message to a specified Parameter
102  The same MIDI Message can map to one or more parameters
103  One Parameter can be mapped from multiple MIDI messages
104 
105  In general usage, these properties only apply to AU's that implement the MIDI API
106  AU Instruments (type=='aumu') and Music Effects (type == 'aumf')
107 
108  These properties are used in the Global scope. The scope and element members of the structure describe
109  the scope and element of the parameter. In all usages, mScope, mElement and mParameterID must be
110  correctly specified.
111 
112 
113  * The AUParameterMIDIMapping Structure
114 
115  Command mStatus mData1
116  Note Off 0x8n Note Num
117  Note On 0x9n Note Num
118  Key Pressure 0xAn Note Num
119  Control Change 0xBn ControllerID
120  Patch Change 0xCn Patch Num
121  Channel Pressure DxDn 0 (Unused)
122  Pitch Bend 0xEn 0 (Unused)
123 
124  (where n is 0-0xF to correspond to MIDI channels 1-16)
125 
126  Details:
127 
128  In general MIDI Commands can be mapped to either a specific channel as specified in the mStatus bit.
129  If the kAUParameterMIDIMapping_AnyChannelFlag bit is set mStatus is a MIDI channel message, then the
130  MIDI channel number in the status byte is ignored; the mapping is from the specified MIDI message on ANY channel.
131 
132  For note commands (note on, note off, key pressure), the MIDI message can trigger either with just a specific
133  note number, or any note number if the kAUParameterMIDIMapping_AnyNoteFlag bit is set. In these instances, the
134  note number is used as the trigger value (for instance, a note message could be used to set the
135  cut off frequency of a filter).
136 
137  The Properties:
138 
139  kAudioUnitProperty_AllParameterMIDIMappings array of AUParameterMIDIMapping (read/write)
140  This property is used to both retreive and set the current mapping state between (some/many/all of) its parameters
141  and MIDI messages. When set, it should replace any previous mapped settings the AU had.
142 
143  If this property is implemented by a non-MIDI capable AU (such as an 'aufx' type), then the property is
144  read only, and recommends a suggested set of mappings for the host to perform. In this case, it is the
145  host's responsibility to map MIDI message to the AU parameters. As described previously, there are a set
146  of default mappings (see AudioToolbox/AUMIDIController.h) that the host can recommend to the user
147  in this circumstance.
148 
149  This property's size will be very dynamic, depending on the number of mappings currently in affect, so the
150  caller should always get the size of the property first before retrieving it. The AU should return an error
151  if the caller doesn't provide enough space to return all of the current mappings.
152 
153  kAudioUnitProperty_AddParameterMIDIMapping array of AUParameterMIDIMapping (write only)
154  This property is used to Add mappings to the existing set of mappings the AU possesses. It does NOT replace
155  any existing mappings.
156 
157  kAudioUnitProperty_RemoveParameterMIDIMapping array of AUParameterMIDIMapping (write only)
158  This property is used to remove the specified mappings from the AU. If a mapping is specified that does not
159  currently exist in the AU, then it should just be ignored.
160 
161  kAudioUnitProperty_HotMapParameterMIDIMapping AUParameterMIDIMapping (read/write)
162  This property is used in two ways, determined by the value supplied by the caller.
163  (1) If a mapping struct is provided, then that struct provides *all* of the information that the AU should
164  use to map the parameter, *except* for the MIDI message. The AU should then listen for the next MIDI message
165  and associate that MIDI message with the supplied AUParameter mapping. When this MIDI message is received and
166  the mapping made, the AU should also issue a notification on this property
167  (kAudioUnitProperty_HotMapParameterMIDIMapping) to indicate to the host that the mapping has been made. The host
168  can then retrieve the mapping that was made by getting the value of this property.
169 
170  To avoid possible confusion, it is recommended that once the host has retrieved this mapping (if it is
171  presenting a UI to describe the mappings for example), that it then clears the mapping state as described next.
172 
173  Thus, the only time this property will return a valid value is when the AU has made a mapping. If the AU's mapping
174  state has been cleared (or it has not been asked to make a mapping), then the AU should return
175  kAudioUnitErr_InvalidPropertyValue if the host tries to read this value.
176 
177  (2) If the value passed in is NULL, then if the AU had a parameter that it was in the process of mapping, it
178  should disregard that (stop listening to the MIDI messages to create a mapping) and discard the partially
179  mapped struct. If the value is NULL and the AU is not in the process of mapping, the AU can ignore the request.
180 
181  At all times, the _AllMappings property will completely describe the current known state of the AU's mappings
182  of MIDI messages to parameters.
183 */
184 
185 
186 /*
187  When mapping, it is recommended that LSB controllers are in general not mapped (ie. the controller range of 32 < 64)
188  as many host parsers will map 14 bit control values. If you know (or can present an option) that the host deals with
189  7 bit controllers only, then these controller ID's can be mapped of course.
190 */
191 
192 
193 struct MIDIValueTransformer {
194  virtual double tolinear(double) = 0;
195  virtual double fromlinear(double) = 0;
196 #if DEBUG
197  // suppress warning
198  virtual ~MIDIValueTransformer() { }
199 #endif
200 };
201 
202 struct MIDILinearTransformer : public MIDIValueTransformer {
203  virtual double tolinear(double x) { return x; }
204  virtual double fromlinear(double x) { return x; }
205 };
206 
207 struct MIDILogTransformer : public MIDIValueTransformer {
208  virtual double tolinear(double x) { return log(std::max(x, .00001)); }
209  virtual double fromlinear(double x) { return exp(x); }
210 };
211 
212 struct MIDIExpTransformer : public MIDIValueTransformer {
213  virtual double tolinear(double x) { return exp(x); }
214  virtual double fromlinear(double x) { return log(std::max(x, .00001)); }
215 };
216 
217 struct MIDISqrtTransformer : public MIDIValueTransformer {
218  virtual double tolinear(double x) { return x < 0. ? -(sqrt(-x)) : sqrt(x); }
219  virtual double fromlinear(double x) { return x < 0. ? -(x * x) : x * x; }
220 };
221 
222 struct MIDISquareTransformer : public MIDIValueTransformer {
223  virtual double tolinear(double x) { return x < 0. ? -(x * x) : x * x; }
224  virtual double fromlinear(double x) { return x < 0. ? -(sqrt(-x)) : sqrt(x); }
225 };
226 
227 struct MIDICubeRtTransformer : public MIDIValueTransformer {
228  virtual double tolinear(double x) { return x < 0. ? -(pow(-x, 1./3.)) : pow(x, 1./3.); }
229  virtual double fromlinear(double x) { return x * x * x; }
230 };
231 
232 struct MIDICubeTransformer : public MIDIValueTransformer {
233  virtual double tolinear(double x) { return x * x * x; }
234  virtual double fromlinear(double x) { return x < 0. ? -(pow(-x, 1./3.)) : pow(x, 1./3.); }
235 };
236 
237 
238 class CAAUMIDIMap : public AUParameterMIDIMapping {
239 
240 public:
241 // variables for more efficient parsing of MIDI to Param value
242  Float32 mMinValue;
243  Float32 mMaxValue;
244  MIDIValueTransformer *mTransType;
245 
246 // methods
247  static MIDIValueTransformer *GetTransformer (UInt32 inFlags);
248 
249  CAAUMIDIMap() { memset(this, 0, sizeof(CAAUMIDIMap)); }
250  CAAUMIDIMap (const AUParameterMIDIMapping& inMap)
251  {
252  memset(this, 0, sizeof(CAAUMIDIMap));
253  memcpy (this, &inMap, sizeof(inMap));
254  }
255  CAAUMIDIMap (AudioUnitScope inScope, AudioUnitElement inElement, AudioUnitParameterID inParam)
256  {
257  memset(this, 0, sizeof(CAAUMIDIMap));
258  mScope = inScope;
259  mElement = inElement;
260  mParameterID = inParam;
261  }
262 
263 
264  bool IsValid () const { return mStatus != 0; }
265 
266  // returns -1 if any channel bit is set
267  SInt32 Channel () const { return IsAnyChannel() ? -1 : (mStatus & 0xF); }
268  bool IsAnyChannel () const {
269  return mFlags & kAUParameterMIDIMapping_AnyChannelFlag;
270  }
271  // preserves the existing channel info in the status byte
272  // preserves any previously set mFlags value
273  void SetAnyChannel (bool inFlag)
274  {
275  if (inFlag)
276  mFlags |= kAUParameterMIDIMapping_AnyChannelFlag;
277  else
278  mFlags &= ~kAUParameterMIDIMapping_AnyChannelFlag;
279  }
280 
281  bool IsAnyNote () const {
282  return (mFlags & kAUParameterMIDIMapping_AnyNoteFlag) != 0;
283  }
284  // preserves the existing key num in the mData1 byte
285  // preserves any previously set mFlags value
286  void SetAnyNote (bool inFlag)
287  {
288  if (inFlag)
289  mFlags |= kAUParameterMIDIMapping_AnyNoteFlag;
290  else
291  mFlags &= ~kAUParameterMIDIMapping_AnyNoteFlag;
292  }
293 
294  bool IsToggle() const { return (mFlags & kAUParameterMIDIMapping_Toggle) != 0; }
295  void SetToggle (bool inFlag)
296  {
297  if (inFlag)
298  mFlags |= kAUParameterMIDIMapping_Toggle;
299  else
300  mFlags &= ~kAUParameterMIDIMapping_Toggle;
301  }
302 
303  bool IsBipolar() const { return (mFlags & kAUParameterMIDIMapping_Bipolar) != 0; }
304  // inUseOnValue is valid ONLY if inFlag is true
305  void SetBipolar (bool inFlag, bool inUseOnValue = false)
306  {
307  if (inFlag) {
308  mFlags |= kAUParameterMIDIMapping_Bipolar;
309  if (inUseOnValue)
310  mFlags |= kAUParameterMIDIMapping_Bipolar_On;
311  else
312  mFlags &= ~kAUParameterMIDIMapping_Bipolar_On;
313  } else {
314  mFlags &= ~kAUParameterMIDIMapping_Bipolar;
315  mFlags &= ~kAUParameterMIDIMapping_Bipolar_On;
316  }
317  }
318  bool IsBipolar_OnValue () const { return (mFlags & kAUParameterMIDIMapping_Bipolar_On) != 0; }
319 
320  bool IsSubRange () const { return (mFlags & kAUParameterMIDIMapping_SubRange) != 0; }
321  void SetSubRange (Float32 inStartValue, Float32 inStopValue)
322  {
323  mFlags |= kAUParameterMIDIMapping_SubRange;
324 
325  mSubRangeMin = inStartValue;
326  mSubRangeMax = inStopValue;
327  }
328 
329  void SetParamRange(Float32 minValue, Float32 maxValue)
330  {
331  mMinValue = minValue;
332  mMaxValue = maxValue;
333  }
334 
335  // this will retain the subrange values previously set.
336  void SetSubRange (bool inFlag)
337  {
338  if (inFlag)
339  mFlags |= kAUParameterMIDIMapping_SubRange;
340  else
341  mFlags &= ~kAUParameterMIDIMapping_SubRange;
342  }
343 
344  bool IsAnyValue() const{return !IsBipolar();}
345  bool IsOnValue() const{return IsBipolar_OnValue();}
346  bool IsOffValue() const{return IsBipolar();}
347 
348  bool IsNoteOff () const { return ((mStatus & 0xF0) == 0x80); }
349  bool IsNoteOn () const { return ((mStatus & 0xF0) == 0x90); }
350 
351  bool IsKeyPressure () const { return ((mStatus & 0xF0) == 0xA0); }
352 
353  bool IsKeyEvent () const { return (mStatus > 0x7F) && (mStatus < 0xB0); }
354 
355  bool IsPatchChange () const { return ((mStatus & 0xF0) == 0xC0); }
356  bool IsChannelPressure () const { return ((mStatus & 0xF0) == 0xD0); }
357  bool IsPitchBend () const { return ((mStatus & 0xF0) == 0xE0); }
358  bool IsControlChange () const { return ((mStatus & 0xF0) == 0xB0); }
359 
360 
361  void SetControllerOnValue(){SetBipolar(true,true);}
362  void SetControllerOffValue(){SetBipolar(true,false);}
363  void SetControllerAnyValue(){SetBipolar(false,false);}
364 
365  // All of these Set calls will reset the mFlags field based on the
366  // anyChannel param value
367  void SetNoteOff (UInt8 key, SInt8 channel, bool anyChannel = false)
368  {
369  mStatus = 0x80 | (channel & 0xF);
370  mData1 = key;
371  mFlags = (anyChannel ? kAUParameterMIDIMapping_AnyChannelFlag : 0);
372 
373  }
374 
375  void SetNoteOn (UInt8 key, SInt8 channel, bool anyChannel = false)
376  {
377  mStatus = 0x90 | (channel & 0xF);
378  mData1 = key;
379  mFlags = (anyChannel ? kAUParameterMIDIMapping_AnyChannelFlag : 0);
380  }
381 
382  void SetPolyKey (UInt8 key, SInt8 channel, bool anyChannel = false)
383  {
384  mStatus = 0xA0 | (channel & 0xF);
385  mData1 = key;
386  mFlags = (anyChannel ? kAUParameterMIDIMapping_AnyChannelFlag : 0);
387  }
388 
389  void SetControlChange (UInt8 controllerID, SInt8 channel, bool anyChannel = false)
390  {
391  mStatus = 0xB0 | (channel & 0xF);
392  mData1 = controllerID;
393  mFlags = (anyChannel ? kAUParameterMIDIMapping_AnyChannelFlag : 0);
394  }
395 
396  void SetPatchChange (UInt8 patchChange, SInt8 channel, bool anyChannel = false)
397  {
398  mStatus = 0xC0 | (channel & 0xF);
399  mData1 = patchChange;
400  mFlags = (anyChannel ? kAUParameterMIDIMapping_AnyChannelFlag : 0);
401  }
402 
403  void SetChannelPressure (SInt8 channel, bool anyChannel = false)
404  {
405  mStatus = 0xD0 | (channel & 0xF);
406  mData1 = 0;
407  mFlags = (anyChannel ? kAUParameterMIDIMapping_AnyChannelFlag : 0);
408  }
409 
410  void SetPitchBend (SInt8 channel, bool anyChannel = false)
411  {
412  mStatus = 0xE0 | (channel & 0xF);
413  mData1 = 0;
414  mFlags = (anyChannel ? kAUParameterMIDIMapping_AnyChannelFlag : 0);
415  }
416 
417 
418  Float32 ParamValueFromMIDILinear (Float32 inLinearValue) const
419  {
420  Float32 low, high;
421  if (IsSubRange()){
422  low = mSubRangeMin;
423  high = mSubRangeMax;
424  }
425  else {
426  low = mMinValue;
427  high = mMaxValue;
428  }
429 
430 
431  // WE ARE ASSUMING YOU HAVE SET THIS UP PROPERLY!!!!! (or this will crash cause it will be NULL)
432  return mTransType->fromlinear((inLinearValue * (high - low)) + low);
433  }
434 
435 
436  // The CALLER of this method must ensure that the status byte's MIDI Command (ignoring the channel) matches!!!
437  bool MIDI_Matches (UInt8 inChannel, UInt8 inData1, UInt8 inData2, Float32 &outLinear) const;
438 
439  void Print () const;
440 
441  void Save (CFPropertyListRef &outData) const;
442  void Restore (CFDictionaryRef inData);
443 
444  static void SaveAsMapPList (AudioUnit inUnit,
445  const AUParameterMIDIMapping * inMappings,
446  UInt32 inNumMappings,
447  CFPropertyListRef &outData,
448  CFStringRef inName = NULL);
449 
450  // inNumMappings describes how much memory is allocated in outMappings
451  static void RestoreFromMapPList (const CFDictionaryRef inData,
452  AUParameterMIDIMapping * outMappings,
453  UInt32 inNumMappings);
454 
455  static UInt32 NumberOfMaps (const CFDictionaryRef inData);
456 };
457 
458 
459  // these sorting operations sort for run-time efficiency based on the MIDI messages
460 inline bool operator== (const CAAUMIDIMap &a, const CAAUMIDIMap &b)
461 {
462  // ignore channel first
463  return (((a.mStatus & 0xF0) == (b.mStatus & 0xF0))
464  && (a.mData1 == b.mData1)
465  && ((a.mStatus & 0xF) == (b.mStatus & 0xf)) // now compare the channel
466  && (a.mParameterID == b.mParameterID)
467  && (a.mElement == b.mElement)
468  && (a.mScope == b.mScope));
469 
470  // reserved field comparisons - ignored until/if they are used
471 }
472 
473 inline bool operator< (const CAAUMIDIMap &a, const CAAUMIDIMap &b)
474 {
475  if ((a.mStatus & 0xF0) != (b.mStatus & 0xF0))
476  return ((a.mStatus & 0xF0) < (b.mStatus & 0xF0));
477 
478  if (a.mData1 != b.mData1)
479  return (a.mData1 < b.mData1);
480 
481  if ((a.mStatus & 0xF) != (b.mStatus & 0xf)) // now compare the channel
482  return ((a.mStatus & 0xF) < (b.mStatus & 0xf));
483 
484 // reserved field comparisons - ignored until/if they are used
485 
486 // we're sorting this by MIDI, so we don't really care how the rest is sorted
487  return ((a.mParameterID < b.mParameterID)
488  && (a.mElement < b.mElement)
489  && (a.mScope < b.mScope));
490 }
491 
492 
493 
494 class CompareMIDIMap {
495  int compare (const CAAUMIDIMap &a, const CAAUMIDIMap &b)
496  {
497  if ((a.mStatus & 0xF0) < (b.mStatus & 0xF0))
498  return -1;
499  if ((a.mStatus & 0xF0) > (b.mStatus & 0xF0))
500  return 1;
501 
502  // note event
503  if (a.mStatus < 0xB0 || a.mStatus >= 0xD0)
504  return 0;
505  if (a.mData1 > b.mData1) return 1;
506  if (a.mData1 < b.mData1) return -1;
507  return 0;
508  }
509 
510 public:
511  bool operator() (const CAAUMIDIMap &a, const CAAUMIDIMap &b) {
512  return compare (a, b) < 0;
513  }
514  bool Finish (const CAAUMIDIMap &a, const CAAUMIDIMap &b) {
515  return compare (a, b) != 0;
516  }
517 };
518 
519 
520 /*
521  usage: To find potential mapped events for a given status byte, where mMMapEvents is a sorted vec
522  CompareMIDIMap comparObj;
523  sortVecIter lower_iter = std::lower_bound(mMMapEvents.begin(), mMMapEvents.end(), inStatusByte, compareObj);
524  for (;lower_iter < mMMapEvents.end(); ++lower_iter) {
525  // then, see if we go out of the status byte range, using the Finish method
526  if (compareObj.Finish(map, tempMap)) // tempMap is a CAAUMIDIMap object with the status/dataByte 1 set
527  break;
528  // ...
529  }
530 
531  in the for loop you call the MIDI_Matches call, to see if the MIDI event matches a given AUMIDIParam mapping
532  special note: you HAVE to transform note on (with vel zero) events to the note off status byte
533 */
534 
535 #endif
bool TTFOUNDATION_EXPORT operator==(const TTObject &anObject, const TTObject &anotherObject)
Compare two objects for equality.
Definition: TTObject.cpp:167