Jamoma API  0.6.0.a19
AUInstrumentBase.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 #include "AUInstrumentBase.h"
42 
43 #if DEBUG
44  #define DEBUG_PRINT 0
45  #define DEBUG_PRINT_RENDER 0
46 #endif
47 
48 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
49 
50 const UInt32 kEventQueueSize = 1024;
51 
52 AUInstrumentBase::AUInstrumentBase(
53  ComponentInstance inInstance,
54  UInt32 numInputs,
55  UInt32 numOutputs,
56  UInt32 numGroups,
57  UInt32 numParts)
58  : MusicDeviceBase(inInstance, numInputs, numOutputs, numGroups, numParts),
59  mAbsoluteSampleFrame(0),
60  mEventQueue(kEventQueueSize),
61  mNumNotes(0),
62  mNumActiveNotes(0),
63  mMaxActiveNotes(0),
64  mNotes(0),
65  mNoteSize(0)
66 {
67 #if DEBUG_PRINT
68  printf("new AUInstrumentBase\n");
69 #endif
70  mFreeNotes.mState = kNoteState_Free;
71 }
72 
73 
74 AUInstrumentBase::~AUInstrumentBase()
75 {
76 #if DEBUG_PRINT
77  printf("delete AUInstrumentBase\n");
78 #endif
79 }
80 
81 AUElement* AUInstrumentBase::CreateElement( AudioUnitScope scope,
82  AudioUnitElement element)
83 {
84 #if DEBUG_PRINT
85  printf("AUInstrumentBase::CreateElement %d %d\n", scope, element);
86 #endif
87  switch (scope)
88  {
89  case kAudioUnitScope_Group :
90  return new SynthGroupElement(this, element);
91  case kAudioUnitScope_Part :
92  return new SynthPartElement(this, element);
93  default :
94  return AUBase::CreateElement(scope, element);
95  }
96 }
97 
98 
99 void AUInstrumentBase::SetNotes(UInt32 inNumNotes, UInt32 inMaxActiveNotes, SynthNote* inNotes, UInt32 inNoteDataSize)
100 {
101 #if DEBUG_PRINT
102  printf("AUInstrumentBase::SetNotes %d %d %08X %d\n", inNumNotes, inMaxActiveNotes, inNotes, inNoteDataSize);
103 #endif
104  mNumNotes = inNumNotes;
105  mMaxActiveNotes = inMaxActiveNotes;
106  mNoteSize = inNoteDataSize;
107  mNotes = inNotes;
108 
109  for (UInt32 i=0; i<mNumNotes; ++i)
110  {
111  SynthNote *note = GetNote(i);
112  note->Reset();
113  mFreeNotes.AddNote(note);
114  }
115 }
116 
117 UInt32 AUInstrumentBase::CountActiveNotes()
118 {
119  // debugging tool.
120  UInt32 sum = 0;
121  for (UInt32 i=0; i<mNumNotes; ++i)
122  {
123  SynthNote *note = GetNote(i);
124  if (note->mState <= kNoteState_Released)
125  sum++;
126  }
127  return sum;
128 }
129 
130 void AUInstrumentBase::AddFreeNote(SynthNote* inNote)
131 {
132  if (inNote->mState != kNoteState_FastReleased)
133  DecNumActiveNotes();
134 #if DEBUG_PRINT
135  printf("AUInstrumentBase::AddFreeNote mNumActiveNotes %lu\n", mNumActiveNotes);
136 #endif
137  mFreeNotes.AddNote(inNote);
138 }
139 
140 OSStatus AUInstrumentBase::Initialize()
141 {
142 /*
143 TO DO:
144  Currently ValidFormat will check and validate that the num channels is not being
145  changed if the AU doesn't support the SupportedNumChannels property - which is correct
146 
147  What needs to happen here is that IFF the AU does support this property, (ie, the AU
148  can be configured to have different num channels than its original configuration) then
149  the state of the AU at Initialization needs to be validated.
150 
151  This is work still to be done - see AUEffectBase for the kind of logic that needs to be applied here
152 */
153 
154  // override to call SetNotes
155 
156  mNoteIDCounter = 128; // reset this every time we initialise
157  mAbsoluteSampleFrame = 0;
158  return noErr;
159 }
160 
161 void AUInstrumentBase::Cleanup()
162 {
163 }
164 
165 
166 OSStatus AUInstrumentBase::Reset( AudioUnitScope inScope,
167  AudioUnitElement inElement)
168 {
169 #if DEBUG_PRINT
170  printf("AUInstrumentBase::Reset\n");
171 #endif
172  if (inScope == kAudioUnitScope_Global)
173  {
174  // kill all notes..
175  mFreeNotes.Empty();
176  for (UInt32 i=0; i<mNumNotes; ++i)
177  {
178  SynthNote *note = GetNote(i);
179  if (note->IsSounding())
180  note->Kill(0);
181  note->ListRemove();
182  mFreeNotes.AddNote(note);
183  }
184  mNumActiveNotes = 0;
185  mAbsoluteSampleFrame = 0;
186 
187  // empty lists.
188  UInt32 numGroups = Groups().GetNumberOfElements();
189  for (UInt32 j = 0; j < numGroups; ++j)
190  {
191  SynthGroupElement *group = (SynthGroupElement*)Groups().GetElement(j);
192  group->Reset();
193  }
194  }
195  return MusicDeviceBase::Reset(inScope, inElement);
196 }
197 
198 void AUInstrumentBase::PerformEvents(const AudioTimeStamp& inTimeStamp)
199 {
200 #if DEBUG_PRINT_RENDER
201  printf("AUInstrumentBase::PerformEvents\n");
202 #endif
203  SynthEvent *event;
204  SynthGroupElement *group;
205 
206  while ((event = mEventQueue.ReadItem()) != NULL)
207  {
208 #if DEBUG_PRINT_RENDER
209  printf("event %08X %d\n", event, event->GetEventType());
210 #endif
211  switch(event->GetEventType())
212  {
213  case SynthEvent::kEventType_NoteOn :
214  RealTimeStartNote(GetElForGroupID (event->GetGroupID()), event->GetNoteID(),
215  event->GetOffsetSampleFrame(), *event->GetParams());
216  break;
217  case SynthEvent::kEventType_NoteOff :
218  RealTimeStopNote(event->GetGroupID(), event->GetNoteID(),
219  event->GetOffsetSampleFrame());
220  break;
221  case SynthEvent::kEventType_SustainOn :
222  group = GetElForGroupID (event->GetGroupID());
223  group->SustainOn(event->GetOffsetSampleFrame());
224  break;
225  case SynthEvent::kEventType_SustainOff :
226  group = GetElForGroupID (event->GetGroupID());
227  group->SustainOff(event->GetOffsetSampleFrame());
228  break;
229  case SynthEvent::kEventType_SostenutoOn :
230  group = GetElForGroupID (event->GetGroupID());
231  group->SostenutoOn(event->GetOffsetSampleFrame());
232  break;
233  case SynthEvent::kEventType_SostenutoOff :
234  group = GetElForGroupID (event->GetGroupID());
235  group->SostenutoOff(event->GetOffsetSampleFrame());
236  break;
237  case SynthEvent::kEventType_AllNotesOff :
238  group = GetElForGroupID (event->GetGroupID());
239  group->AllNotesOff(event->GetOffsetSampleFrame());
240  break;
241  case SynthEvent::kEventType_AllSoundOff :
242  group = GetElForGroupID (event->GetGroupID());
243  group->AllSoundOff(event->GetOffsetSampleFrame());
244  break;
245  case SynthEvent::kEventType_ResetAllControllers :
246  group = GetElForGroupID (event->GetGroupID());
247  group->ResetAllControllers(event->GetOffsetSampleFrame());
248  break;
249  }
250 
251  mEventQueue.AdvanceReadPtr();
252  }
253 }
254 
255 
256 OSStatus AUInstrumentBase::Render( AudioUnitRenderActionFlags & ioActionFlags,
257  const AudioTimeStamp & inTimeStamp,
258  UInt32 inNumberFrames)
259 {
260  PerformEvents(inTimeStamp);
261 
262  UInt32 numOutputs = Outputs().GetNumberOfElements();
263  for (UInt32 j = 0; j < numOutputs; ++j)
264  {
265  AudioBufferList& bufferList = GetOutput(j)->GetBufferList();
266  for (UInt32 k = 0; k < bufferList.mNumberBuffers; ++k)
267  {
268  memset(bufferList.mBuffers[k].mData, 0, bufferList.mBuffers[k].mDataByteSize);
269  }
270  }
271 
272  UInt32 numGroups = Groups().GetNumberOfElements();
273  for (UInt32 j = 0; j < numGroups; ++j)
274  {
275  SynthGroupElement *group = (SynthGroupElement*)Groups().GetElement(j);
276  OSStatus err = group->Render(inNumberFrames);
277  if (err) return err;
278  }
279  mAbsoluteSampleFrame += inNumberFrames;
280  return noErr;
281 }
282 
283 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
284 // AUInstrumentBase::ValidFormat
285 //
286 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
287 bool AUInstrumentBase::ValidFormat( AudioUnitScope inScope,
288  AudioUnitElement inElement,
289  const CAStreamBasicDescription & inNewFormat)
290 {
291  // if the AU supports this, then we should just let this go through to the Init call
292  if (SupportedNumChannels (NULL))
293  return MusicDeviceBase::ValidFormat(inScope, inElement, inNewFormat);
294 
295  bool isGood = MusicDeviceBase::ValidFormat (inScope, inElement, inNewFormat);
296  if (!isGood) return false;
297 
298  // if we get to here, then the basic criteria is that the
299  // num channels cannot change on an existing bus
300  AUIOElement *el = GetIOElement (inScope, inElement);
301  return (el->GetStreamFormat().NumberChannels() == inNewFormat.NumberChannels());
302 }
303 
304 
305 bool AUInstrumentBase::StreamFormatWritable( AudioUnitScope scope,
306  AudioUnitElement element)
307 {
308  return IsInitialized() ? false : true;
309 }
310 
311 OSStatus AUInstrumentBase::RealTimeStartNote( SynthGroupElement *inGroup,
312  NoteInstanceID inNoteInstanceID,
313  UInt32 inOffsetSampleFrame,
314  const MusicDeviceNoteParams &inParams)
315 {
316  return noErr;
317 }
318 
319 SynthGroupElement * AUInstrumentBase::GetElForGroupID (MusicDeviceGroupID inGroupID)
320 {
321  AUScope & groups = Groups();
322  unsigned int numEls = groups.GetNumberOfElements();
323  SynthGroupElement* unassignedEl = NULL;
324 
325  for (unsigned int i = 0; i < numEls; ++i) {
326  SynthGroupElement* el = reinterpret_cast<SynthGroupElement*>(groups.GetElement(i));
327  if (el->GroupID() == inGroupID)
328  return el;
329  if (el->GroupID() == SynthGroupElement::kUnassignedGroup) {
330  unassignedEl = el;
331  break; // we fill this up from the start of the group scope vector
332  }
333  }
334  if (unassignedEl) {
335  unassignedEl->SetGroupID(inGroupID);
336  return unassignedEl;
337  }
338  throw static_cast<OSStatus>(kAudioUnitErr_InvalidElement);
339 }
340 
341 OSStatus AUInstrumentBase::RealTimeStopNote(
342  MusicDeviceGroupID inGroupID,
343  NoteInstanceID inNoteInstanceID,
344  UInt32 inOffsetSampleFrame)
345 {
346 #if DEBUG_PRINT
347  printf("AUInstrumentBase::RealTimeStopNote %d %d\n", inGroupID, inNoteInstanceID);
348 #endif
349 
350  SynthGroupElement *gp = (inGroupID == kMusicNoteEvent_Unused
351  ? GetElForNoteID (inNoteInstanceID)
352  : GetElForGroupID(inGroupID));
353 
354  gp->NoteOff (inNoteInstanceID, inOffsetSampleFrame);
355 
356  return noErr;
357 }
358 
359 SynthGroupElement * AUInstrumentBase::GetElForNoteID (NoteInstanceID inNoteID)
360 {
361 #if DEBUG_PRINT
362  printf("GetElForNoteID id %d\n", (int)inNoteID);
363 #endif
364  if (!mNotes) throw std::runtime_error("no notes");
365 
366  for (unsigned int i = 0; i < mNumNotes; ++i) {
367  if (inNoteID == mNotes[i].GetNoteID()) {
368  return mNotes[i].GetGroup();
369  }
370  }
371  throw static_cast<OSStatus>(kAudioUnitErr_InvalidElement);
372 }
373 
374 OSStatus AUInstrumentBase::StartNote( MusicDeviceInstrumentID inInstrument,
375  MusicDeviceGroupID inGroupID,
376  NoteInstanceID * outNoteInstanceID,
377  UInt32 inOffsetSampleFrame,
378  const MusicDeviceNoteParams &inParams)
379 {
380 #if DEBUG_PRINT
381  printf("AUInstrumentBase::StartNote %d\n", inGroupID);
382 #endif
383  OSStatus err = noErr;
384 
385  NoteInstanceID noteID;
386  if (outNoteInstanceID) {
387  noteID = NextNoteID();
388  *outNoteInstanceID = noteID;
389  } else
390  noteID = (UInt32)inParams.mPitch;
391 
392  if (InRenderThread ())
393  {
394  err = RealTimeStartNote(
395  GetElForGroupID(inGroupID),
396  noteID,
397  inOffsetSampleFrame,
398  inParams);
399  }
400  else
401  {
402  SynthEvent *event = mEventQueue.WriteItem();
403  if (!event) return -1; // queue full
404 
405  event->Set(
406  SynthEvent::kEventType_NoteOn,
407  inGroupID,
408  noteID,
409  inOffsetSampleFrame,
410  &inParams
411  );
412 
413  mEventQueue.AdvanceWritePtr();
414  }
415  return err;
416 }
417 
418 OSStatus AUInstrumentBase::StopNote( MusicDeviceGroupID inGroupID,
419  NoteInstanceID inNoteInstanceID,
420  UInt32 inOffsetSampleFrame)
421 {
422 #if DEBUG_PRINT
423  printf("AUInstrumentBase::StopNote %d %d\n", inGroupID, inNoteInstanceID);
424 #endif
425  OSStatus err = noErr;
426 
427  if (InRenderThread ())
428  {
429  err = RealTimeStopNote(
430  inGroupID,
431  inNoteInstanceID,
432  inOffsetSampleFrame);
433  }
434  else
435  {
436  SynthEvent *event = mEventQueue.WriteItem();
437  if (!event) return -1; // queue full
438 
439  event->Set(
440  SynthEvent::kEventType_NoteOff,
441  inGroupID,
442  inNoteInstanceID,
443  inOffsetSampleFrame,
444  NULL
445  );
446 
447  mEventQueue.AdvanceWritePtr();
448  }
449  return err;
450 }
451 
452 OSStatus AUInstrumentBase::SendPedalEvent(MusicDeviceGroupID inGroupID, UInt32 inEventType, UInt32 inOffsetSampleFrame)
453 {
454 
455  if (InRenderThread ())
456  {
457  SynthGroupElement *group = GetElForGroupID(inGroupID);
458  switch (inEventType)
459  {
460  case SynthEvent::kEventType_SustainOn :
461  group->SustainOn(inOffsetSampleFrame);
462  break;
463  case SynthEvent::kEventType_SustainOff :
464  group->SustainOff(inOffsetSampleFrame);
465  break;
466  case SynthEvent::kEventType_SostenutoOn :
467  group->SostenutoOn(inOffsetSampleFrame);
468  break;
469  case SynthEvent::kEventType_SostenutoOff :
470  group->SostenutoOff(inOffsetSampleFrame);
471  break;
472  case SynthEvent::kEventType_AllNotesOff :
473  group->AllNotesOff(inOffsetSampleFrame);
474  mNumActiveNotes = CountActiveNotes();
475  break;
476  case SynthEvent::kEventType_AllSoundOff :
477  group->AllSoundOff(inOffsetSampleFrame);
478  mNumActiveNotes = CountActiveNotes();
479  break;
480  case SynthEvent::kEventType_ResetAllControllers :
481  group->ResetAllControllers(inOffsetSampleFrame);
482  break;
483  }
484  }
485  else
486  {
487  SynthEvent *event = mEventQueue.WriteItem();
488  if (!event) return -1; // queue full
489 
490  event->Set(inEventType, inGroupID, 0, 0, NULL);
491 
492  mEventQueue.AdvanceWritePtr();
493  }
494  return noErr;
495 }
496 
497 OSStatus AUInstrumentBase::HandleControlChange( UInt8 inChannel,
498  UInt8 inController,
499  UInt8 inValue,
500  UInt32 inStartFrame)
501 {
502  GetControls(inChannel)->mControls[inController] = inValue;
503  switch (inController)
504  {
505  case kMidiController_Sustain :
506  if (inValue >= 64)
507  SendPedalEvent(inChannel, SynthEvent::kEventType_SustainOn, inStartFrame);
508  else
509  SendPedalEvent(inChannel, SynthEvent::kEventType_SustainOff, inStartFrame);
510  break;
511  case kMidiController_Sostenuto :
512  if (inValue >= 64)
513  SendPedalEvent(inChannel, SynthEvent::kEventType_SostenutoOn, inStartFrame);
514  else
515  SendPedalEvent(inChannel, SynthEvent::kEventType_SostenutoOff, inStartFrame);
516  break;
517  }
518  return noErr;
519 }
520 
521 OSStatus AUInstrumentBase::HandlePitchWheel( UInt8 inChannel,
522  UInt8 inPitch1,
523  UInt8 inPitch2,
524  UInt32 inStartFrame)
525 {
526  MidiControls* controls = GetControls(inChannel);
527  controls->mPitchBend = (inPitch2 << 7) | inPitch1;
528  controls->mFPitchBend = (float)((SInt16)controls->mPitchBend - 8192) / 8192.;
529  return noErr;
530 }
531 
532 
533 OSStatus AUInstrumentBase::HandleChannelPressure(UInt8 inChannel,
534  UInt8 inValue,
535  UInt32 inStartFrame)
536 {
537  GetControls(inChannel)->mMonoPressure = inValue;
538  return noErr;
539 }
540 
541 
542 OSStatus AUInstrumentBase::HandleProgramChange( UInt8 inChannel,
543  UInt8 inValue)
544 {
545  GetControls(inChannel)->mMonoPressure = inValue;
546  return noErr;
547 }
548 
549 
550 OSStatus AUInstrumentBase::HandlePolyPressure( UInt8 inChannel,
551  UInt8 inKey,
552  UInt8 inValue,
553  UInt32 inStartFrame)
554 {
555  GetControls(inChannel)->mPolyPressure[inKey] = inValue;
556  return noErr;
557 }
558 
559 
560 OSStatus AUInstrumentBase::HandleResetAllControllers( UInt8 inChannel)
561 {
562  SendPedalEvent (inChannel, SynthEvent::kEventType_ResetAllControllers, 0);
563  return noErr;
564 }
565 
566 
567 OSStatus AUInstrumentBase::HandleAllNotesOff( UInt8 inChannel)
568 {
569  SendPedalEvent (inChannel, SynthEvent::kEventType_AllNotesOff, 0);
570  return noErr;
571 }
572 
573 
574 OSStatus AUInstrumentBase::HandleAllSoundOff( UInt8 inChannel)
575 {
576  SendPedalEvent (inChannel, SynthEvent::kEventType_AllSoundOff, 0);
577  return noErr;
578 }
579 
580 SynthNote* AUInstrumentBase::GetAFreeNote(UInt32 inFrame)
581 {
582 #if DEBUG_PRINT
583  printf("GetAFreeNote size %d\n", mFreeNotes.Length());
584 #endif
585  SynthNote *note = mFreeNotes.mHead;
586  if (note)
587  {
588  mFreeNotes.RemoveNote(note);
589  return note;
590  }
591 
592  return VoiceStealing(inFrame, true);
593 }
594 
595 SynthNote* AUInstrumentBase::VoiceStealing(UInt32 inFrame, bool inKillIt)
596 {
597 
598 #if DEBUG_PRINT
599  printf("enter voice stealing\n");
600 #endif
601  // free list was empty so we need to kill a note.
602  UInt32 startState = inKillIt ? kNoteState_FastReleased : kNoteState_Released;
603  for (UInt32 i = startState; i <= startState; --i)
604  {
605 #if DEBUG_PRINT
606  printf(" steal state %d\n", i);
607 #endif
608  UInt32 numGroups = Groups().GetNumberOfElements();
609  for (UInt32 j = 0; j < numGroups; ++j)
610  {
611  SynthGroupElement *group = (SynthGroupElement*)Groups().GetElement(j);
612 #if DEBUG_PRINT
613  printf(" steal group %d size %d\n", j, group->mNoteList[i].Length());
614 #endif
615  if (group->mNoteList[i].NotEmpty()) {
616 #if DEBUG_PRINT
617  printf("not empty %d %d\n", i, j);
618 #endif
619  SynthNote *note = group->mNoteList[i].FindMostQuietNote();
620  if (inKillIt) {
621 #if DEBUG_PRINT
622  printf("--=== KILL ===---\n");
623 #endif
624  note->mRelativeKillFrame = inFrame;
625  note->Kill(inFrame);
626  group->mNoteList[i].RemoveNote(note);
627  if (i != kNoteState_FastReleased)
628  DecNumActiveNotes();
629  return note;
630  } else {
631 #if DEBUG_PRINT
632  printf("--=== FAST RELEASE ===---\n");
633 #endif
634  group->mNoteList[i].RemoveNote(note);
635  note->FastRelease(inFrame);
636  group->mNoteList[kNoteState_FastReleased].AddNote(note);
637  DecNumActiveNotes(); // kNoteState_FastReleased counts as inactive for voice stealing purposes.
638  return NULL;
639  }
640  }
641  }
642  }
643 #if DEBUG_PRINT
644  printf("no notes to steal????\n");
645 #endif
646  return NULL; // It should be impossible to get here. It means there were no notes to kill in any state.
647 }
648 
649 
650 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
651 
652 AUMonotimbralInstrumentBase::AUMonotimbralInstrumentBase(
653  ComponentInstance inInstance,
654  UInt32 numInputs,
655  UInt32 numOutputs,
656  UInt32 numGroups,
657  UInt32 numParts)
658  : AUInstrumentBase(inInstance, numInputs, numOutputs, numGroups, numParts)
659 {
660 }
661 
662 OSStatus AUMonotimbralInstrumentBase::RealTimeStartNote(
663  SynthGroupElement *inGroup,
664  NoteInstanceID inNoteInstanceID,
665  UInt32 inOffsetSampleFrame,
666  const MusicDeviceNoteParams &inParams)
667 {
668 #if DEBUG_PRINT_RENDER
669  printf("AUMonotimbralInstrumentBase::RealTimeStartNote %d\n", inNoteInstanceID);
670 #endif
671 
672  if (NumActiveNotes() + 1 > MaxActiveNotes())
673  {
674  VoiceStealing(inOffsetSampleFrame, false);
675  }
676  SynthNote *note = GetAFreeNote(inOffsetSampleFrame);
677  if (!note) return -1;
678 
679  IncNumActiveNotes();
680  note->AttackNote(NULL, inGroup, inNoteInstanceID,
681  mAbsoluteSampleFrame + inOffsetSampleFrame, inOffsetSampleFrame, inParams);
682 
683  inGroup->mNoteList[kNoteState_Attacked].AddNote(note);
684  return noErr;
685 }
686 
687 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
688 
689 
690 OSStatus AUMultitimbralInstrumentBase::GetPropertyInfo(AudioUnitPropertyID inID,
691  AudioUnitScope inScope,
692  AudioUnitElement inElement,
693  UInt32 & outDataSize,
694  Boolean & outWritable)
695 {
696  OSStatus result = noErr;
697 
698  switch (inID)
699  {
700  case kMusicDeviceProperty_PartGroup:
701  if (inScope != kAudioUnitScope_Part) return kAudioUnitErr_InvalidScope;
702  outDataSize = sizeof(UInt32);
703  outWritable = true;
704  break;
705 
706  default:
707  result = AUInstrumentBase::GetPropertyInfo (inID, inScope, inElement, outDataSize, outWritable);
708  }
709  return result;
710 }
711 
712 OSStatus AUMultitimbralInstrumentBase::GetProperty( AudioUnitPropertyID inID,
713  AudioUnitScope inScope,
714  AudioUnitElement inElement,
715  void * outData)
716 {
717  OSStatus result = noErr;
718 
719  switch (inID)
720  {
721  case kMusicDeviceProperty_PartGroup:
722  if (inScope != kAudioUnitScope_Group) return kAudioUnitErr_InvalidScope;
723  // ??
724  return -1; //unimpl
725  break;
726 
727  default:
728  result = AUInstrumentBase::GetProperty (inID, inScope, inElement, outData);
729  }
730 
731  return result;
732 }
733 
734 
735 
736 OSStatus AUMultitimbralInstrumentBase::SetProperty( AudioUnitPropertyID inID,
737  AudioUnitScope inScope,
738  AudioUnitElement inElement,
739  const void * inData,
740  UInt32 inDataSize)
741 {
742  OSStatus result = noErr;
743 
744  switch (inID)
745  {
746  case kMusicDeviceProperty_PartGroup:
747  if (inScope != kAudioUnitScope_Group) return kAudioUnitErr_InvalidScope;
748  // ??
749  return -1; //unimpl
750  break;
751 
752  default:
753  result = MusicDeviceBase::SetProperty (inID, inScope, inElement, inData, inDataSize);
754  }
755 
756  return result;
757 }
758 
759 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
760