Jamoma API  0.6.0.a19
AUMIDIBase.cpp
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 /*=============================================================================
42  AUMIDIBase.cpp
43 
44 =============================================================================*/
45 
46 #include "AUMIDIBase.h"
47 #include <CoreMIDI/CoreMIDI.h>
48 
49 //temporaray location
50 enum
51 {
52  kMidiMessage_NoteOff = 0x80,
53  kMidiMessage_NoteOn = 0x90,
54  kMidiMessage_PolyPressure = 0xA0,
55  kMidiMessage_ControlChange = 0xB0,
56  kMidiMessage_ProgramChange = 0xC0,
57  kMidiMessage_ChannelPressure = 0xD0,
58  kMidiMessage_PitchWheel = 0xE0,
59 
60  kMidiController_AllSoundOff = 120,
61  kMidiController_ResetAllControllers = 121,
62  kMidiController_AllNotesOff = 123
63 };
64 
65 AUMIDIBase::AUMIDIBase(AUBase* inBase)
66  : mAUBaseInstance (*inBase)
67 {
68 #if CA_AUTO_MIDI_MAP
69  mMapManager = new CAAUMIDIMapManager();
70 #endif
71 }
72 
73 AUMIDIBase::~AUMIDIBase()
74 {
75 #if CA_AUTO_MIDI_MAP
76  if (mMapManager)
77  delete mMapManager;
78 #endif
79 }
80 
81 #if TARGET_API_MAC_OSX
82 ComponentResult AUMIDIBase::DelegateGetPropertyInfo(AudioUnitPropertyID inID,
83  AudioUnitScope inScope,
84  AudioUnitElement inElement,
85  UInt32 & outDataSize,
86  Boolean & outWritable)
87 {
88  if (inScope != kAudioUnitScope_Global) return kAudioUnitErr_InvalidScope;
89  if (inElement != 0) return kAudioUnitErr_InvalidElement;
90 
91  ComponentResult result = noErr;
92 
93  switch (inID) {
94  case kMusicDeviceProperty_MIDIXMLNames:
95  if (GetXMLNames(NULL) == noErr) {
96  outDataSize = sizeof(CFURLRef);
97  outWritable = false;
98  } else
99  result = kAudioUnitErr_InvalidProperty;
100  break;
101 
102 #if CA_AUTO_MIDI_MAP
103  case kAudioUnitProperty_AllParameterMIDIMappings:
104  outWritable = true;
105  outDataSize = sizeof (AUParameterMIDIMapping)*mMapManager->NumMaps();
106  result = noErr;
107  break;
108 
109  case kAudioUnitProperty_HotMapParameterMIDIMapping:
110  outWritable = true;
111  outDataSize = sizeof (AUParameterMIDIMapping);
112  result = noErr;
113  break;
114 
115  case kAudioUnitProperty_AddParameterMIDIMapping:
116  outWritable = true;
117  outDataSize = sizeof (AUParameterMIDIMapping);
118  result = noErr;
119  break;
120 
121  case kAudioUnitProperty_RemoveParameterMIDIMapping:
122  outWritable = true;
123  outDataSize = sizeof (AUParameterMIDIMapping);
124  result = noErr;
125  break;
126 #endif
127 
128  default:
129  result = kAudioUnitErr_InvalidProperty;
130  break;
131  }
132  return result;
133 }
134 
135 ComponentResult AUMIDIBase::DelegateGetProperty( AudioUnitPropertyID inID,
136  AudioUnitScope inScope,
137  AudioUnitElement inElement,
138  void * outData)
139 {
140  if (inScope != kAudioUnitScope_Global) return kAudioUnitErr_InvalidScope;
141  if (inElement != 0) return kAudioUnitErr_InvalidElement;
142 
143  ComponentResult result;
144 
145  switch (inID) {
146  case kMusicDeviceProperty_MIDIXMLNames:
147  result = GetXMLNames((CFURLRef *)outData);
148  break;
149 
150 #if CA_AUTO_MIDI_MAP
151  case kAudioUnitProperty_AllParameterMIDIMappings:{
152  AUParameterMIDIMapping* maps = (static_cast<AUParameterMIDIMapping*>(outData));
153  mMapManager->GetMaps(maps);
154 // printf ("GETTING MAPS\n");
155 // mMapManager->Print();
156  result = noErr;
157  break;
158  }
159 
160  case kAudioUnitProperty_HotMapParameterMIDIMapping:{
161  AUParameterMIDIMapping * map = (static_cast<AUParameterMIDIMapping*>(outData));
162  mMapManager->GetHotParameterMap (*map);
163  result = noErr;
164  break;
165  }
166 #endif
167 
168  default:
169  result = kAudioUnitErr_InvalidProperty;
170  break;
171  }
172  return result;
173 }
174 
175 ComponentResult AUMIDIBase::DelegateSetProperty( AudioUnitPropertyID inID,
176  AudioUnitScope inScope,
177  AudioUnitElement inElement,
178  const void * inData,
179  UInt32 inDataSize)
180 {
181  if (inScope != kAudioUnitScope_Global) return kAudioUnitErr_InvalidScope;
182  if (inElement != 0) return kAudioUnitErr_InvalidElement;
183 
184  OSStatus result;
185 
186  switch (inID) {
187 #if CA_AUTO_MIDI_MAP
188  case kAudioUnitProperty_AddParameterMIDIMapping:{
189  AUParameterMIDIMapping * maps = (AUParameterMIDIMapping*)inData;
190  mMapManager->SortedInsertToParamaterMaps (maps, (inDataSize / sizeof(AUParameterMIDIMapping)), mAUBaseInstance);
191  mAUBaseInstance.PropertyChanged (kAudioUnitProperty_AllParameterMIDIMappings, kAudioUnitScope_Global, 0);
192  result = noErr;
193  break;
194  }
195 
196  case kAudioUnitProperty_RemoveParameterMIDIMapping:{
197  AUParameterMIDIMapping * maps = (AUParameterMIDIMapping*)inData;
198  bool didChange;
199  mMapManager->SortedRemoveFromParameterMaps(maps, (inDataSize / sizeof(AUParameterMIDIMapping)), didChange);
200  if (didChange)
201  mAUBaseInstance.PropertyChanged (kAudioUnitProperty_AllParameterMIDIMappings, kAudioUnitScope_Global, 0);
202  result = noErr;
203  break;
204  }
205 
206  case kAudioUnitProperty_HotMapParameterMIDIMapping:{
207  AUParameterMIDIMapping & map = *((AUParameterMIDIMapping*)inData);
208  mMapManager->SetHotMapping (map);
209  result = noErr;
210  break;
211  }
212  case kAudioUnitProperty_AllParameterMIDIMappings:{
213  AUParameterMIDIMapping * mappings = (AUParameterMIDIMapping*)inData;
214  mMapManager->ReplaceAllMaps (mappings, (inDataSize / sizeof(AUParameterMIDIMapping)), mAUBaseInstance);
215  result = noErr;
216  break;
217  }
218 #endif
219 
220  default:
221  result = kAudioUnitErr_InvalidProperty;
222  break;
223  }
224  return result;
225 }
226 
227 
228 
229 #endif //TARGET_API_MAC_OSX
230 
231 
232 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
233 #pragma mark ____MidiDispatch
234 
235 
236 inline const Byte * NextMIDIEvent(const Byte *event, const Byte *end)
237 {
238  Byte c = *event;
239  switch (c >> 4) {
240  default: // data byte -- assume in sysex
241  while ((*++event & 0x80) == 0 && event < end)
242  ;
243  break;
244  case 0x8:
245  case 0x9:
246  case 0xA:
247  case 0xB:
248  case 0xE:
249  event += 3;
250  break;
251  case 0xC:
252  case 0xD:
253  event += 2;
254  break;
255  case 0xF:
256  switch (c) {
257  case 0xF0:
258  while ((*++event & 0x80) == 0 && event < end)
259  ;
260  break;
261  case 0xF1:
262  case 0xF3:
263  event += 2;
264  break;
265  case 0xF2:
266  event += 3;
267  break;
268  default:
269  ++event;
270  break;
271  }
272  }
273  return (event >= end) ? end : event;
274 }
275 
276 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
277 // AUMIDIBase::HandleMIDIPacketList
278 //
279 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
280 ComponentResult AUMIDIBase::HandleMIDIPacketList(const MIDIPacketList *pktlist)
281 {
282  if (!mAUBaseInstance.IsInitialized()) return kAudioUnitErr_Uninitialized;
283 
284  int nPackets = pktlist->numPackets;
285  const MIDIPacket *pkt = pktlist->packet;
286 
287  while (nPackets-- > 0) {
288  const Byte *event = pkt->data, *packetEnd = event + pkt->length;
289  long startFrame = (long)pkt->timeStamp;
290  while (event < packetEnd) {
291  Byte status = event[0];
292  if (status & 0x80) {
293  // really a status byte (not sysex continuation)
294  HandleMidiEvent(status & 0xF0, status & 0x0F, event[1], event[2], startFrame);
295  // note that we're generating a bogus channel number for system messages (0xF0-FF)
296  }
297  event = NextMIDIEvent(event, packetEnd);
298  }
299  pkt = reinterpret_cast<const MIDIPacket *>(packetEnd);
300  }
301  return noErr;
302 }
303 
304 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
305 // AUMIDIBase::HandleMidiEvent
306 //
307 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
308 OSStatus AUMIDIBase::HandleMidiEvent(UInt8 status, UInt8 channel, UInt8 data1, UInt8 data2, UInt32 inStartFrame)
309 {
310  if (!mAUBaseInstance.IsInitialized()) return kAudioUnitErr_Uninitialized;
311 
312 #if CA_AUTO_MIDI_MAP
313 // you potentially have a choice to make here - if a param mapping matches, do you still want to process the
314 // MIDI event or not. The default behaviour is to continue on with the MIDI event.
315  if (mMapManager->HandleHotMapping (status, channel, data1, mAUBaseInstance)) {
316  mAUBaseInstance.PropertyChanged (kAudioUnitProperty_HotMapParameterMIDIMapping, kAudioUnitScope_Global, 0);
317  }
318  else {
319  mMapManager->FindParameterMapEventMatch(status, channel, data1, data2, inStartFrame, mAUBaseInstance);
320  }
321 #endif
322 
323  OSStatus result = noErr;
324 
325  switch(status)
326  {
327  case kMidiMessage_NoteOn:
328  if(data2)
329  {
330  result = HandleNoteOn(channel, data1, data2, inStartFrame);
331  }
332  else
333  {
334  // zero velocity translates to note off
335  result = HandleNoteOff(channel, data1, data2, inStartFrame);
336  }
337  break;
338 
339  case kMidiMessage_NoteOff:
340  result = HandleNoteOff(channel, data1, data2, inStartFrame);
341  break;
342 
343  default:
344  result = HandleNonNoteEvent (status, channel, data1, data2, inStartFrame);
345  break;
346  }
347 
348  return result;
349 }
350 
351 OSStatus AUMIDIBase::HandleNonNoteEvent (UInt8 status, UInt8 channel, UInt8 data1, UInt8 data2, UInt32 inStartFrame)
352 {
353  OSStatus result = noErr;
354 
355  switch (status)
356  {
357  case kMidiMessage_PitchWheel:
358  result = HandlePitchWheel(channel, data1, data2, inStartFrame);
359  break;
360 
361  case kMidiMessage_ProgramChange:
362  result = HandleProgramChange(channel, data1);
363  break;
364 
365  case kMidiMessage_ChannelPressure:
366  result = HandleChannelPressure(channel, data1, inStartFrame);
367  break;
368 
369  case kMidiMessage_ControlChange:
370  {
371  switch (data1) {
372  case kMidiController_AllNotesOff:
373  result = HandleAllNotesOff(channel);
374  break;
375 
376  case kMidiController_ResetAllControllers:
377  result = HandleResetAllControllers(channel);
378  break;
379 
380  case kMidiController_AllSoundOff:
381  result = HandleAllSoundOff(channel);
382  break;
383 
384  default:
385  result = HandleControlChange(channel, data1, data2, inStartFrame);
386  break;
387  }
388  break;
389  }
390  case kMidiMessage_PolyPressure:
391  result = HandlePolyPressure (channel, data1, data2, inStartFrame);
392  break;
393  }
394  return result;
395 }
396 
397 ComponentResult AUMIDIBase::SysEx (const UInt8 * inData,
398  UInt32 inLength)
399 {
400  if (!mAUBaseInstance.IsInitialized()) return kAudioUnitErr_Uninitialized;
401 
402  return HandleSysEx(inData, inLength );
403 }
404 
405 
406 
407 #if TARGET_OS_MAC
408  #if __LP64__
409  // comp instance, parameters in forward order
410  #define PARAM(_typ, _name, _index, _nparams) \
411  _typ _name = *(_typ *)&params->params[_index + 1];
412  #else
413  // parameters in reverse order, then comp instance
414  #define PARAM(_typ, _name, _index, _nparams) \
415  _typ _name = *(_typ *)&params->params[_nparams - 1 - _index];
416  #endif
417 #elif TARGET_OS_WIN32
418  // (no comp instance), parameters in forward order
419  #define PARAM(_typ, _name, _index, _nparams) \
420  _typ _name = *(_typ *)&params->params[_index];
421 #endif
422 
423 
424 ComponentResult AUMIDIBase::ComponentEntryDispatch( ComponentParameters * params,
425  AUMIDIBase * This)
426 {
427  if (This == NULL) return paramErr;
428 
429  ComponentResult result;
430 
431  switch (params->what) {
432  case kMusicDeviceMIDIEventSelect:
433  {
434  PARAM(UInt32, pbinStatus, 0, 4);
435  PARAM(UInt32, pbinData1, 1, 4);
436  PARAM(UInt32, pbinData2, 2, 4);
437  PARAM(UInt32, pbinOffsetSampleFrame, 3, 4);
438  result = This->MIDIEvent(pbinStatus, pbinData1, pbinData2, pbinOffsetSampleFrame);
439  }
440  break;
441  case kMusicDeviceSysExSelect:
442  {
443  PARAM(const UInt8 *, pbinData, 0, 2);
444  PARAM(UInt32, pbinLength, 1, 2);
445  result = This->SysEx(pbinData, pbinLength);
446  }
447  break;
448 
449  default:
450  result = badComponentSelector;
451  break;
452  }
453 
454  return result;
455 }
456