summaryrefslogtreecommitdiff
path: root/libs/appleutility/CoreAudio/PublicUtility/CAAUMIDIMap.h
blob: 33d0c2e266c7e838289aeb913347352bf685a47f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
/*
     File: CAAUMIDIMap.h
 Abstract: Part of CoreAudio Utility Classes
  Version: 1.1

 Disclaimer: IMPORTANT:  This Apple software is supplied to you by Apple
 Inc. ("Apple") in consideration of your agreement to the following
 terms, and your use, installation, modification or redistribution of
 this Apple software constitutes acceptance of these terms.  If you do
 not agree with these terms, please do not use, install, modify or
 redistribute this Apple software.

 In consideration of your agreement to abide by the following terms, and
 subject to these terms, Apple grants you a personal, non-exclusive
 license, under Apple's copyrights in this original Apple software (the
 "Apple Software"), to use, reproduce, modify and redistribute the Apple
 Software, with or without modifications, in source and/or binary forms;
 provided that if you redistribute the Apple Software in its entirety and
 without modifications, you must retain this notice and the following
 text and disclaimers in all such redistributions of the Apple Software.
 Neither the name, trademarks, service marks or logos of Apple Inc. may
 be used to endorse or promote products derived from the Apple Software
 without specific prior written permission from Apple.  Except as
 expressly stated in this notice, no other rights or licenses, express or
 implied, are granted by Apple herein, including but not limited to any
 patent rights that may be infringed by your derivative works or by other
 works in which the Apple Software may be incorporated.

 The Apple Software is provided by Apple on an "AS IS" basis.  APPLE
 MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
 THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
 FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
 OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.

 IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
 MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
 AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
 STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGE.

 Copyright (C) 2014 Apple Inc. All Rights Reserved.

*/
#ifndef __CAAUMIDIMap_h_
#define __CAAUMIDIMap_h_

#include <AudioUnit/AudioUnitProperties.h>
#include <algorithm>

/*
enum {
	kAUParameterMIDIMapping_AnyChannelFlag		= (1L << 0),
		// If this flag is set and mStatus is a MIDI channel message, then the MIDI channel number
		// in the status byte is ignored; the mapping is from the specified MIDI message on ANY channel.

	kAUParameterMIDIMapping_AnyNoteFlag			= (1L << 1),
		// If this flag is set and mStatus is a Note On, Note Off, or Polyphonic Pressure message,
		// the message's note number is ignored; the mapping is from ANY note number.

	kAUParameterMIDIMapping_SubRange			= (1L << 2),
		// set this flag if the midi control should map only to a sub-range of the parameter's value
		// then specify that range in the mSubRangeMin and mSubRangeMax members

	kAUParameterMIDIMapping_Toggle				= (1L << 3),
		// this is only useful for boolean typed parameters. When set, it means that the parameter's
		// value should be toggled (if true, become false and vice versa) when the represented MIDI message
		// is received

	kAUParameterMIDIMapping_Bipolar				= (1L << 4),
		// this can be set to when mapping a MIDI Controller to indicate that the parameter (typically a boolean
		// style parameter) will only have its value changed to either the on or off state of a MIDI controller message
		// (0 < 64 is off, 64 < 127 is on) such as the sustain pedal. The seeting of the next flag
		// (kAUParameterMIDIMapping_Bipolar_On) determine whether the parameter is mapped to the on or off
		// state of the controller
	kAUParameterMIDIMapping_Bipolar_On			= (1L << 5)
		// only a valid flag if kAUParameterMIDIMapping_Bipolar is set
};

// The reserved fields here are being used to reserve space (as well as align to 64 bit size) for future use
// When/If these fields are used, the names of the fields will be changed to reflect their functionality
// so, apps should NOT refer to these reserved fields directly by name
typedef struct AUParameterMIDIMapping
{
	AudioUnitScope			mScope;
	AudioUnitElement		mElement;
	AudioUnitParameterID	mParameterID;
	UInt32					mFlags;
	Float32					mSubRangeMin;
	Float32					mSubRangeMax;
	UInt8					mStatus;
	UInt8					mData1;
	UInt8					reserved1; // MUST be set to zero
	UInt8					reserved2; // MUST be set to zero
	UInt32					reserved3; // MUST be set to zero
} AUParameterMIDIMapping;
*/

/*
Parameter To MIDI Mapping Properties
These properties are used to:
Describe a current set of mappings between MIDI messages and Parameter value setting
Create a mapping between a parameter and a MIDI message through either:
- explicitly adding (or removing) the mapping
- telling the AU to hot-map the next MIDI message to a specified Parameter
	The same MIDI Message can map to one or more parameters
	One Parameter can be mapped from multiple MIDI messages

	In general usage, these properties only apply to AU's that implement the MIDI API
	AU Instruments (type=='aumu') and Music Effects (type == 'aumf')

	These properties are used in the Global scope. The scope and element members of the structure describe
	the scope and element of the parameter. In all usages, mScope, mElement and mParameterID must be
	correctly specified.


	* The AUParameterMIDIMapping Structure

	Command				mStatus			mData1
	Note Off			0x8n			Note Num
	Note On				0x9n			Note Num
	Key Pressure		0xAn			Note Num
	Control Change		0xBn			ControllerID
	Patch Change		0xCn			Patch Num
	Channel Pressure	DxDn			0 (Unused)
	Pitch Bend			0xEn			0 (Unused)

	(where n is 0-0xF to correspond to MIDI channels 1-16)

		Details:

	In general MIDI Commands can be mapped to either a specific channel as specified in the mStatus bit.
	If the kAUParameterMIDIMapping_AnyChannelFlag bit is set mStatus is a MIDI channel message, then the
	MIDI channel number in the status byte is ignored; the mapping is from the specified MIDI message on ANY channel.

	For note commands (note on, note off, key pressure), the MIDI message can trigger either with just a specific
	note number, or any note number if the kAUParameterMIDIMapping_AnyNoteFlag bit is set. In these instances, the
	note number is used as the trigger value (for instance, a note message could be used to set the
											  cut off frequency of a filter).

 The Properties:

	kAudioUnitProperty_AllParameterMIDIMappings							array of AUParameterMIDIMapping (read/write)
	This property is used to both retreive and set the current mapping state between (some/many/all of) its parameters
	and MIDI messages. When set, it should replace any previous mapped settings the AU had.

	If this property is implemented by a non-MIDI capable AU (such as an 'aufx' type), then the property is
	read only, and recommends a suggested set of mappings for the host to perform. In this case, it is the
	host's responsibility to map MIDI message to the AU parameters. As described previously, there are a set
	of default mappings (see AudioToolbox/AUMIDIController.h) that the host can recommend to the user
	in this circumstance.

	This property's size will be very dynamic, depending on the number of mappings currently in affect, so the
	caller should always get the size of the property first before retrieving it. The AU should return an error
	if the caller doesn't provide enough space to return all of the current mappings.

	kAudioUnitProperty_AddParameterMIDIMapping							array of AUParameterMIDIMapping (write only)
	This property is used to Add mappings to the existing set of mappings the AU possesses. It does NOT replace
	any existing mappings.

	kAudioUnitProperty_RemoveParameterMIDIMapping						array of AUParameterMIDIMapping (write only)
	This property is used to remove the specified mappings from the AU. If a mapping is specified that does not
	currently exist in the AU, then it should just be ignored.

	kAudioUnitProperty_HotMapParameterMIDIMapping								AUParameterMIDIMapping (read/write)
	This property is used in two ways, determined by the value supplied by the caller.
	(1) If a mapping struct is provided, then that struct provides *all* of the information that the AU should
	use to map the parameter, *except* for the MIDI message. The AU should then listen for the next MIDI message
	and associate that MIDI message with the supplied AUParameter mapping. When this MIDI message is received and
	the mapping made, the AU should also issue a notification on this property
	(kAudioUnitProperty_HotMapParameterMIDIMapping) to indicate to the host that the mapping has been made. The host
	can then retrieve the mapping that was made by getting the value of this property.

	To avoid possible confusion, it is recommended that once the host has retrieved this mapping (if it is
	presenting a UI to describe the mappings for example), that it then clears the mapping state as described next.

	Thus, the only time this property will return a valid value is when the AU has made a mapping. If the AU's mapping
	state has been cleared (or it has not been asked to make a mapping), then the AU should return
	kAudioUnitErr_InvalidPropertyValue if the host tries to read this value.

	(2) If the value passed in is NULL, then if the AU had a parameter that it was in the process of mapping, it
	should disregard that (stop listening to the MIDI messages to create a mapping) and discard the partially
	mapped struct. If the value is NULL and the AU is not in the process of mapping, the AU can ignore the request.

	At all times, the _AllMappings property will completely describe the current known state of the AU's mappings
	of MIDI messages to parameters.
*/


/*
	When mapping, it is recommended that LSB controllers are in general not mapped (ie. the controller range of 32 < 64)
	as many host parsers will map 14 bit control values. If you know (or can present an option) that the host deals with
	7 bit controllers only, then these controller ID's can be mapped of course.
*/


struct MIDIValueTransformer {
	virtual double  tolinear(double) = 0;
	virtual double  fromlinear(double) = 0;
#if DEBUG
	// suppress warning
	virtual ~MIDIValueTransformer() { }
#endif
};

struct MIDILinearTransformer : public MIDIValueTransformer {
	virtual double  tolinear(double x) { return x; }
	virtual double  fromlinear(double x) { return x; }
};

struct MIDILogTransformer : public MIDIValueTransformer {
	virtual double  tolinear(double x) { return log(std::max(x, .00001)); }
	virtual double  fromlinear(double x) { return exp(x); }
};

struct MIDIExpTransformer : public MIDIValueTransformer {
	virtual double  tolinear(double x) { return exp(x); }
	virtual double  fromlinear(double x) { return log(std::max(x, .00001)); }
};

struct MIDISqrtTransformer : public MIDIValueTransformer {
	virtual double  tolinear(double x) { return x < 0. ? -(sqrt(-x)) : sqrt(x); }
	virtual double  fromlinear(double x) { return x < 0. ? -(x * x) : x * x; }
};

struct MIDISquareTransformer : public MIDIValueTransformer {
	virtual double  tolinear(double x) { return x < 0. ? -(x * x) : x * x; }
	virtual double  fromlinear(double x) { return x < 0. ? -(sqrt(-x)) : sqrt(x); }
};

struct MIDICubeRtTransformer : public MIDIValueTransformer {
	virtual double  tolinear(double x) { return x < 0. ? -(pow(-x, 1./3.)) : pow(x, 1./3.); }
	virtual double  fromlinear(double x) { return x * x * x; }
};

struct MIDICubeTransformer : public MIDIValueTransformer {
	virtual double  tolinear(double x) { return x * x * x; }
	virtual double  fromlinear(double x) { return x < 0. ? -(pow(-x, 1./3.)) : pow(x, 1./3.); }
};


class CAAUMIDIMap : public AUParameterMIDIMapping {

public:
// variables for more efficient parsing of MIDI to Param value
	Float32						mMinValue;
	Float32						mMaxValue;
	MIDIValueTransformer		*mTransType;

// methods
	static MIDIValueTransformer *GetTransformer (UInt32 inFlags);

								CAAUMIDIMap() { memset(this, 0, sizeof(CAAUMIDIMap)); }
								CAAUMIDIMap (const AUParameterMIDIMapping& inMap)
								{
									memset(this, 0, sizeof(CAAUMIDIMap));
									memcpy (this, &inMap, sizeof(inMap));
								}
								CAAUMIDIMap (AudioUnitScope inScope, AudioUnitElement inElement, AudioUnitParameterID inParam)
								{
									memset(this, 0, sizeof(CAAUMIDIMap));
									mScope = inScope;
									mElement = inElement;
									mParameterID = inParam;
								}


	bool						IsValid () const { return mStatus != 0; }

	// returns -1 if any channel bit is set
	SInt32						Channel () const { return IsAnyChannel() ? -1 : (mStatus & 0xF); }
	bool						IsAnyChannel () const {
									return mFlags & kAUParameterMIDIMapping_AnyChannelFlag;
								}
									// preserves the existing channel info in the status byte
									// preserves any previously set mFlags value
	void						SetAnyChannel (bool inFlag)
								{
									if (inFlag)
										mFlags |= kAUParameterMIDIMapping_AnyChannelFlag;
									else
										mFlags &= ~kAUParameterMIDIMapping_AnyChannelFlag;
								}

	bool						IsAnyNote () const {
									return (mFlags & kAUParameterMIDIMapping_AnyNoteFlag) != 0;
								}
									// preserves the existing key num in the mData1 byte
									// preserves any previously set mFlags value
	void						SetAnyNote (bool inFlag)
								{
									if (inFlag)
										mFlags |= kAUParameterMIDIMapping_AnyNoteFlag;
									else
										mFlags &= ~kAUParameterMIDIMapping_AnyNoteFlag;
								}

	bool						IsToggle() const { return (mFlags & kAUParameterMIDIMapping_Toggle) != 0; }
	void						SetToggle (bool inFlag)
								{
									if (inFlag)
										mFlags |= kAUParameterMIDIMapping_Toggle;
									else
										mFlags &= ~kAUParameterMIDIMapping_Toggle;
								}

	bool						IsBipolar() const { return (mFlags & kAUParameterMIDIMapping_Bipolar) != 0; }
									// inUseOnValue is valid ONLY if inFlag is true
	void						SetBipolar (bool inFlag, bool inUseOnValue = false)
								{
									if (inFlag) {
										mFlags |= kAUParameterMIDIMapping_Bipolar;
										if (inUseOnValue)
											mFlags |= kAUParameterMIDIMapping_Bipolar_On;
										else
											mFlags &= ~kAUParameterMIDIMapping_Bipolar_On;
									} else {
										mFlags &= ~kAUParameterMIDIMapping_Bipolar;
										mFlags &= ~kAUParameterMIDIMapping_Bipolar_On;
									}
								}
	bool						IsBipolar_OnValue () const { return (mFlags & kAUParameterMIDIMapping_Bipolar_On) != 0; }

	bool						IsSubRange () const { return (mFlags & kAUParameterMIDIMapping_SubRange) != 0; }
	void						SetSubRange (Float32 inStartValue, Float32 inStopValue)
								{
									mFlags |= kAUParameterMIDIMapping_SubRange;

									mSubRangeMin = inStartValue;
									mSubRangeMax = inStopValue;
								}

	void						SetParamRange(Float32 minValue, Float32 maxValue)
								{
									mMinValue = minValue;
									mMaxValue = maxValue;
								}

								// this will retain the subrange values previously set.
	void						SetSubRange (bool inFlag)
								{
									if (inFlag)
										mFlags |= kAUParameterMIDIMapping_SubRange;
									else
										mFlags &= ~kAUParameterMIDIMapping_SubRange;
								}

	bool						IsAnyValue() const{return !IsBipolar();}
	bool						IsOnValue() const{return IsBipolar_OnValue();}
	bool						IsOffValue() const{return IsBipolar();}

	bool						IsNoteOff () const { return ((mStatus & 0xF0) == 0x80); }
	bool						IsNoteOn () const { return ((mStatus & 0xF0) == 0x90); }

	bool						IsKeyPressure () const { return ((mStatus & 0xF0) == 0xA0); }

	bool						IsKeyEvent () const { return (mStatus > 0x7F) && (mStatus < 0xB0); }

	bool						IsPatchChange () const { return ((mStatus & 0xF0) == 0xC0); }
	bool						IsChannelPressure () const { return ((mStatus & 0xF0) == 0xD0); }
	bool						IsPitchBend () const { return ((mStatus & 0xF0) == 0xE0); }
	bool						IsControlChange () const { return ((mStatus & 0xF0) == 0xB0); }


	void						SetControllerOnValue(){SetBipolar(true,true);}
	void						SetControllerOffValue(){SetBipolar(true,false);}
	void						SetControllerAnyValue(){SetBipolar(false,false);}

	// All of these Set calls will reset the mFlags field based on the
	// anyChannel param value
	void						SetNoteOff (UInt8 key, SInt8 channel, bool anyChannel = false)
								{
									mStatus = 0x80 | (channel & 0xF);
									mData1 = key;
									mFlags = (anyChannel ? kAUParameterMIDIMapping_AnyChannelFlag : 0);

								}

	void						SetNoteOn (UInt8 key, SInt8 channel, bool anyChannel = false)
								{
									mStatus = 0x90 | (channel & 0xF);
									mData1 = key;
									mFlags = (anyChannel ? kAUParameterMIDIMapping_AnyChannelFlag : 0);
								}

	void						SetPolyKey (UInt8 key, SInt8 channel, bool anyChannel = false)
								{
									mStatus = 0xA0 | (channel & 0xF);
									mData1 = key;
									mFlags = (anyChannel ? kAUParameterMIDIMapping_AnyChannelFlag : 0);
								}

	void						SetControlChange (UInt8 controllerID, SInt8 channel, bool anyChannel = false)
								{
									mStatus = 0xB0 | (channel & 0xF);
									mData1 = controllerID;
									mFlags = (anyChannel ? kAUParameterMIDIMapping_AnyChannelFlag : 0);
								}

	void						SetPatchChange (UInt8 patchChange, SInt8 channel, bool anyChannel = false)
								{
									mStatus = 0xC0 | (channel & 0xF);
									mData1 = patchChange;
									mFlags = (anyChannel ? kAUParameterMIDIMapping_AnyChannelFlag : 0);
								}

	void						SetChannelPressure (SInt8 channel, bool anyChannel = false)
								{
									mStatus = 0xD0 | (channel & 0xF);
									mData1 = 0;
									mFlags = (anyChannel ? kAUParameterMIDIMapping_AnyChannelFlag : 0);
								}

	void						SetPitchBend (SInt8 channel, bool anyChannel = false)
								{
									mStatus = 0xE0 | (channel & 0xF);
									mData1 = 0;
									mFlags = (anyChannel ? kAUParameterMIDIMapping_AnyChannelFlag : 0);
								}


	Float32						ParamValueFromMIDILinear (Float32		inLinearValue) const
	{
								Float32 low, high;
								if (IsSubRange()){
									low = mSubRangeMin;
									high = mSubRangeMax;
								}
								else {
									low = mMinValue;
									high = mMaxValue;
								}


								// WE ARE ASSUMING YOU HAVE SET THIS UP PROPERLY!!!!! (or this will crash cause it will be NULL)
								return (Float32)mTransType->fromlinear((inLinearValue * (high - low)) + low);
	}


		// The CALLER of this method must ensure that the status byte's MIDI Command (ignoring the channel) matches!!!
	bool						MIDI_Matches (UInt8 inChannel, UInt8 inData1, UInt8 inData2, Float32 &outLinear) const;

	void						Print () const;

	void						Save (CFPropertyListRef &outData) const;
	void						Restore (CFDictionaryRef inData);

	static void					SaveAsMapPList (AudioUnit						inUnit,
											const AUParameterMIDIMapping		* inMappings,
											UInt32								inNumMappings,
											CFPropertyListRef					&outData,
											CFStringRef							inName = NULL);

									// inNumMappings describes how much memory is allocated in outMappings
	static void					RestoreFromMapPList (const CFDictionaryRef			inData,
														AUParameterMIDIMapping		* outMappings,
														UInt32						inNumMappings);

	static UInt32				NumberOfMaps (const CFDictionaryRef inData);
};


	// these sorting operations sort for run-time efficiency based on the MIDI messages
inline bool operator== (const CAAUMIDIMap &a, const CAAUMIDIMap &b)
{
		// ignore channel first
	return (((a.mStatus & 0xF0) == (b.mStatus & 0xF0))
			&& (a.mData1 == b.mData1)
			&& ((a.mStatus & 0xF) == (b.mStatus & 0xf))  // now compare the channel
			&&  (a.mParameterID == b.mParameterID)
			&& (a.mElement == b.mElement)
			&& (a.mScope == b.mScope));

	// reserved field comparisons - ignored until/if they are used
}

inline bool operator< (const CAAUMIDIMap	&a, const CAAUMIDIMap &b)
{
	if ((a.mStatus & 0xF0) != (b.mStatus & 0xF0))
		return ((a.mStatus & 0xF0) < (b.mStatus & 0xF0));

	if (a.mData1 != b.mData1)
		return (a.mData1 < b.mData1);

	if ((a.mStatus & 0xF) != (b.mStatus & 0xf))  // now compare the channel
		return ((a.mStatus & 0xF) < (b.mStatus & 0xf));

// reserved field comparisons - ignored until/if they are used

//		we're sorting this by MIDI, so we don't really care how the rest is sorted
	return	((a.mParameterID < b.mParameterID)
				&& (a.mElement < b.mElement)
				&& (a.mScope < b.mScope));
}



class CompareMIDIMap {
	int compare (const CAAUMIDIMap &a, const CAAUMIDIMap &b)
	{
		if ((a.mStatus & 0xF0) < (b.mStatus & 0xF0))
			return -1;
		if ((a.mStatus & 0xF0) > (b.mStatus & 0xF0))
			return 1;

			// note event
		if (a.mStatus < 0xB0 || a.mStatus >= 0xD0)
			return 0;
		if (a.mData1 > b.mData1) return 1;
		if (a.mData1 < b.mData1) return -1;
		return 0;
	}

public:
	bool operator() (const CAAUMIDIMap &a, const CAAUMIDIMap &b) {
		return compare (a, b) < 0;
	}
	bool Finish (const CAAUMIDIMap &a, const CAAUMIDIMap &b) {
		return compare (a, b) != 0;
	}
};


/*
	usage: To find potential mapped events for a given status byte, where mMMapEvents is a sorted vec
	CompareMIDIMap comparObj;
	sortVecIter lower_iter = std::lower_bound(mMMapEvents.begin(), mMMapEvents.end(), inStatusByte, compareObj);
	for (;lower_iter < mMMapEvents.end(); ++lower_iter) {
		// then, see if we go out of the status byte range, using the Finish method
		if (compareObj.Finish(map, tempMap)) // tempMap is a CAAUMIDIMap object with the status/dataByte 1 set
			break;
	// ...
	}

	in the for loop you call the MIDI_Matches call, to see if the MIDI event matches a given AUMIDIParam mapping
	special note: you HAVE to transform note on (with vel zero) events to the note off status byte
*/

#endif