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