13
0
livetrax/libs/appleutility/CoreAudio/AudioUnits/AUPublic/AUInstrumentBase/AUInstrumentBase.cpp

844 lines
24 KiB
C++

/*
File: AUInstrumentBase.cpp
Abstract: AUInstrumentBase.h
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.
*/
#include "AUInstrumentBase.h"
#include "AUMIDIDefs.h"
#if DEBUG
#define DEBUG_PRINT 0
#define DEBUG_PRINT_NOTE 0
#define DEBUG_PRINT_RENDER 0
#endif
////////////////////////////////////////////////////////////////////////////////////////////////////////////
const UInt32 kEventQueueSize = 1024;
AUInstrumentBase::AUInstrumentBase(
AudioComponentInstance inInstance,
UInt32 numInputs,
UInt32 numOutputs,
UInt32 numGroups,
UInt32 numParts)
: MusicDeviceBase(inInstance, numInputs, numOutputs, numGroups),
mAbsoluteSampleFrame(0),
mEventQueue(kEventQueueSize),
mNumNotes(0),
mNumActiveNotes(0),
mMaxActiveNotes(0),
mNotes(0),
mNoteSize(0),
mInitNumPartEls(numParts)
{
#if DEBUG_PRINT
printf("new AUInstrumentBase\n");
#endif
mFreeNotes.mState = kNoteState_Free;
SetWantsRenderThreadID(true);
}
AUInstrumentBase::~AUInstrumentBase()
{
#if DEBUG_PRINT
printf("delete AUInstrumentBase\n");
#endif
}
AUElement * AUInstrumentBase::CreateElement(AudioUnitScope inScope, AudioUnitElement element)
{
switch (inScope)
{
case kAudioUnitScope_Group:
return new SynthGroupElement(this, element, new MidiControls);
case kAudioUnitScope_Part:
return new SynthPartElement (this, element);
}
return MusicDeviceBase::CreateElement(inScope, element);
}
void AUInstrumentBase::CreateExtendedElements()
{
Parts().Initialize(this, kAudioUnitScope_Part, mInitNumPartEls);
}
AUScope * AUInstrumentBase::GetScopeExtended (AudioUnitScope inScope)
{
if (inScope == kAudioUnitScope_Part)
return &mPartScope;
return NULL;
}
void AUInstrumentBase::SetNotes(UInt32 inNumNotes, UInt32 inMaxActiveNotes, SynthNote* inNotes, UInt32 inNoteDataSize)
{
#if DEBUG_PRINT_NOTE
printf("AUInstrumentBase::SetNotes %d %d %p %d\n", inNumNotes, inMaxActiveNotes, inNotes, inNoteDataSize);
#endif
mNumNotes = inNumNotes;
mMaxActiveNotes = inMaxActiveNotes;
mNoteSize = inNoteDataSize;
mNotes = inNotes;
for (UInt32 i=0; i<mNumNotes; ++i)
{
SynthNote *note = GetNote(i);
note->Reset();
mFreeNotes.AddNote(note);
}
}
UInt32 AUInstrumentBase::CountActiveNotes()
{
// debugging tool.
UInt32 sum = 0;
for (UInt32 i=0; i<mNumNotes; ++i)
{
SynthNote *note = GetNote(i);
if (note->GetState() <= kNoteState_Released)
sum++;
}
return sum;
}
void AUInstrumentBase::AddFreeNote(SynthNote* inNote)
{
// Fast-released notes are already considered inactive and have already decr'd the active count
if (inNote->GetState() < kNoteState_FastReleased) {
DecNumActiveNotes();
}
#if DEBUG_PRINT_NOTE
else {
printf("AUInstrumentBase::AddFreeNote: adding fast-released note %p\n", inNote);
}
printf("AUInstrumentBase::AddFreeNote (%p) mNumActiveNotes %lu\n", inNote, mNumActiveNotes);
#endif
mFreeNotes.AddNote(inNote);
}
OSStatus AUInstrumentBase::Initialize()
{
/*
TO DO:
Currently ValidFormat will check and validate that the num channels is not being
changed if the AU doesn't support the SupportedNumChannels property - which is correct
What needs to happen here is that IFF the AU does support this property, (ie, the AU
can be configured to have different num channels than its original configuration) then
the state of the AU at Initialization needs to be validated.
This is work still to be done - see AUEffectBase for the kind of logic that needs to be applied here
*/
// override to call SetNotes
mNoteIDCounter = 128; // reset this every time we initialise
mAbsoluteSampleFrame = 0;
return noErr;
}
void AUInstrumentBase::Cleanup()
{
mFreeNotes.Empty();
}
OSStatus AUInstrumentBase::Reset( AudioUnitScope inScope,
AudioUnitElement inElement)
{
#if DEBUG_PRINT
printf("AUInstrumentBase::Reset\n");
#endif
if (inScope == kAudioUnitScope_Global)
{
// kill all notes..
mFreeNotes.Empty();
for (UInt32 i=0; i<mNumNotes; ++i)
{
SynthNote *note = GetNote(i);
if (note->IsSounding())
note->Kill(0);
note->ListRemove();
mFreeNotes.AddNote(note);
}
mNumActiveNotes = 0;
mAbsoluteSampleFrame = 0;
// empty lists.
UInt32 numGroups = Groups().GetNumberOfElements();
for (UInt32 j = 0; j < numGroups; ++j)
{
SynthGroupElement *group = (SynthGroupElement*)Groups().GetElement(j);
group->Reset();
}
}
return MusicDeviceBase::Reset(inScope, inElement);
}
void AUInstrumentBase::PerformEvents(const AudioTimeStamp& inTimeStamp)
{
#if DEBUG_PRINT_RENDER
printf("AUInstrumentBase::PerformEvents\n");
#endif
SynthEvent *event;
SynthGroupElement *group;
while ((event = mEventQueue.ReadItem()) != NULL)
{
#if DEBUG_PRINT_RENDER
printf("event %08X %d\n", event, event->GetEventType());
#endif
switch(event->GetEventType())
{
case SynthEvent::kEventType_NoteOn :
RealTimeStartNote(GetElForGroupID (event->GetGroupID()), event->GetNoteID(),
event->GetOffsetSampleFrame(), *event->GetParams());
break;
case SynthEvent::kEventType_NoteOff :
RealTimeStopNote(event->GetGroupID(), event->GetNoteID(),
event->GetOffsetSampleFrame());
break;
case SynthEvent::kEventType_SustainOn :
group = GetElForGroupID (event->GetGroupID());
group->SustainOn(event->GetOffsetSampleFrame());
break;
case SynthEvent::kEventType_SustainOff :
group = GetElForGroupID (event->GetGroupID());
group->SustainOff(event->GetOffsetSampleFrame());
break;
case SynthEvent::kEventType_SostenutoOn :
group = GetElForGroupID (event->GetGroupID());
group->SostenutoOn(event->GetOffsetSampleFrame());
break;
case SynthEvent::kEventType_SostenutoOff :
group = GetElForGroupID (event->GetGroupID());
group->SostenutoOff(event->GetOffsetSampleFrame());
break;
case SynthEvent::kEventType_AllNotesOff :
group = GetElForGroupID (event->GetGroupID());
group->AllNotesOff(event->GetOffsetSampleFrame());
break;
case SynthEvent::kEventType_AllSoundOff :
group = GetElForGroupID (event->GetGroupID());
group->AllSoundOff(event->GetOffsetSampleFrame());
break;
case SynthEvent::kEventType_ResetAllControllers :
group = GetElForGroupID (event->GetGroupID());
group->ResetAllControllers(event->GetOffsetSampleFrame());
break;
}
mEventQueue.AdvanceReadPtr();
}
}
OSStatus AUInstrumentBase::Render( AudioUnitRenderActionFlags & ioActionFlags,
const AudioTimeStamp & inTimeStamp,
UInt32 inNumberFrames)
{
PerformEvents(inTimeStamp);
AUScope &outputs = Outputs();
UInt32 numOutputs = outputs.GetNumberOfElements();
for (UInt32 j = 0; j < numOutputs; ++j)
{
GetOutput(j)->PrepareBuffer(inNumberFrames); // AUBase::DoRenderBus() only does this for the first output element
AudioBufferList& bufferList = GetOutput(j)->GetBufferList();
for (UInt32 k = 0; k < bufferList.mNumberBuffers; ++k)
{
memset(bufferList.mBuffers[k].mData, 0, bufferList.mBuffers[k].mDataByteSize);
}
}
UInt32 numGroups = Groups().GetNumberOfElements();
for (UInt32 j = 0; j < numGroups; ++j)
{
SynthGroupElement *group = (SynthGroupElement*)Groups().GetElement(j);
OSStatus err = group->Render((SInt64)inTimeStamp.mSampleTime, inNumberFrames, outputs);
if (err) return err;
}
mAbsoluteSampleFrame += inNumberFrames;
return noErr;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// AUInstrumentBase::ValidFormat
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool AUInstrumentBase::ValidFormat( AudioUnitScope inScope,
AudioUnitElement inElement,
const CAStreamBasicDescription & inNewFormat)
{
// if the AU supports this, then we should just let this go through to the Init call
if (SupportedNumChannels (NULL))
return MusicDeviceBase::ValidFormat(inScope, inElement, inNewFormat);
bool isGood = MusicDeviceBase::ValidFormat (inScope, inElement, inNewFormat);
if (!isGood) return false;
// if we get to here, then the basic criteria is that the
// num channels cannot change on an existing bus
AUIOElement *el = GetIOElement (inScope, inElement);
return (el->GetStreamFormat().NumberChannels() == inNewFormat.NumberChannels());
}
bool AUInstrumentBase::StreamFormatWritable( AudioUnitScope scope,
AudioUnitElement element)
{
return IsInitialized() ? false : true;
}
OSStatus AUInstrumentBase::RealTimeStartNote( SynthGroupElement *inGroup,
NoteInstanceID inNoteInstanceID,
UInt32 inOffsetSampleFrame,
const MusicDeviceNoteParams &inParams)
{
return noErr;
}
SynthPartElement * AUInstrumentBase::GetPartElement (AudioUnitElement inPartElement)
{
AUScope & parts = Parts();
unsigned int numEls = parts.GetNumberOfElements();
for (unsigned int i = 0; i < numEls; ++i) {
SynthPartElement* el = reinterpret_cast<SynthPartElement*>(parts.GetElement(i));
if (el->GetIndex() == inPartElement) {
return el;
}
}
return NULL;
}
SynthGroupElement * AUInstrumentBase::GetElForGroupID (MusicDeviceGroupID inGroupID)
{
AUScope & groups = Groups();
unsigned int numEls = groups.GetNumberOfElements();
SynthGroupElement* unassignedEl = NULL;
for (unsigned int i = 0; i < numEls; ++i) {
SynthGroupElement* el = reinterpret_cast<SynthGroupElement*>(groups.GetElement(i));
if (el->GroupID() == inGroupID)
return el;
if (el->GroupID() == SynthGroupElement::kUnassignedGroup) {
unassignedEl = el;
break; // we fill this up from the start of the group scope vector
}
}
if (unassignedEl) {
unassignedEl->SetGroupID(inGroupID);
return unassignedEl;
}
throw static_cast<OSStatus>(kAudioUnitErr_InvalidElement);
}
OSStatus AUInstrumentBase::RealTimeStopNote(
MusicDeviceGroupID inGroupID,
NoteInstanceID inNoteInstanceID,
UInt32 inOffsetSampleFrame)
{
#if DEBUG_PRINT
printf("AUInstrumentBase::RealTimeStopNote ch %d id %d\n", inGroupID, inNoteInstanceID);
#endif
SynthGroupElement *gp = (inGroupID == kMusicNoteEvent_Unused
? GetElForNoteID (inNoteInstanceID)
: GetElForGroupID(inGroupID));
if (gp)
{
gp->NoteOff (inNoteInstanceID, inOffsetSampleFrame);
}
return noErr;
}
SynthGroupElement * AUInstrumentBase::GetElForNoteID (NoteInstanceID inNoteID)
{
#if DEBUG_PRINT
printf("GetElForNoteID id %u\n", inNoteID);
#endif
AUScope & groups = Groups();
unsigned int numEls = groups.GetNumberOfElements();
for (unsigned int i = 0; i < numEls; ++i) {
SynthGroupElement* el = reinterpret_cast<SynthGroupElement*>(groups.GetElement(i));
if (el->GetNote(inNoteID) != NULL) // searches for any note state
return el;
}
throw static_cast<OSStatus>(kAudioUnitErr_InvalidElement);
}
OSStatus AUInstrumentBase::StartNote( MusicDeviceInstrumentID inInstrument,
MusicDeviceGroupID inGroupID,
NoteInstanceID * outNoteInstanceID,
UInt32 inOffsetSampleFrame,
const MusicDeviceNoteParams &inParams)
{
OSStatus err = noErr;
NoteInstanceID noteID;
if (outNoteInstanceID) {
noteID = NextNoteID();
*outNoteInstanceID = noteID;
} else
noteID = (UInt32)inParams.mPitch;
#if DEBUG_PRINT
printf("AUInstrumentBase::StartNote ch %u, key %u, offset %u\n", inGroupID, (unsigned) inParams.mPitch, inOffsetSampleFrame);
#endif
if (InRenderThread ())
{
err = RealTimeStartNote(
GetElForGroupID(inGroupID),
noteID,
inOffsetSampleFrame,
inParams);
}
else
{
SynthEvent *event = mEventQueue.WriteItem();
if (!event) return -1; // queue full
event->Set(
SynthEvent::kEventType_NoteOn,
inGroupID,
noteID,
inOffsetSampleFrame,
&inParams
);
mEventQueue.AdvanceWritePtr();
}
return err;
}
OSStatus AUInstrumentBase::StopNote( MusicDeviceGroupID inGroupID,
NoteInstanceID inNoteInstanceID,
UInt32 inOffsetSampleFrame)
{
#if DEBUG_PRINT
printf("AUInstrumentBase::StopNote ch %u, id %u, offset %u\n", (unsigned)inGroupID, (unsigned)inNoteInstanceID, inOffsetSampleFrame);
#endif
OSStatus err = noErr;
if (InRenderThread ())
{
err = RealTimeStopNote(
inGroupID,
inNoteInstanceID,
inOffsetSampleFrame);
}
else
{
SynthEvent *event = mEventQueue.WriteItem();
if (!event) return -1; // queue full
event->Set(
SynthEvent::kEventType_NoteOff,
inGroupID,
inNoteInstanceID,
inOffsetSampleFrame,
NULL
);
mEventQueue.AdvanceWritePtr();
}
return err;
}
OSStatus AUInstrumentBase::SendPedalEvent(MusicDeviceGroupID inGroupID, UInt32 inEventType, UInt32 inOffsetSampleFrame)
{
if (InRenderThread ())
{
SynthGroupElement *group = GetElForGroupID(inGroupID);
if (!group)
return kAudioUnitErr_InvalidElement;
switch (inEventType)
{
case SynthEvent::kEventType_SustainOn :
group->SustainOn(inOffsetSampleFrame);
break;
case SynthEvent::kEventType_SustainOff :
group->SustainOff(inOffsetSampleFrame);
break;
case SynthEvent::kEventType_SostenutoOn :
group->SostenutoOn(inOffsetSampleFrame);
break;
case SynthEvent::kEventType_SostenutoOff :
group->SostenutoOff(inOffsetSampleFrame);
break;
case SynthEvent::kEventType_AllNotesOff :
group->AllNotesOff(inOffsetSampleFrame);
mNumActiveNotes = CountActiveNotes();
break;
case SynthEvent::kEventType_AllSoundOff :
group->AllSoundOff(inOffsetSampleFrame);
mNumActiveNotes = CountActiveNotes();
break;
case SynthEvent::kEventType_ResetAllControllers :
group->ResetAllControllers(inOffsetSampleFrame);
break;
}
}
else
{
SynthEvent *event = mEventQueue.WriteItem();
if (!event) return -1; // queue full
event->Set(inEventType, inGroupID, 0, 0, NULL);
mEventQueue.AdvanceWritePtr();
}
return noErr;
}
OSStatus AUInstrumentBase::HandleControlChange( UInt8 inChannel,
UInt8 inController,
UInt8 inValue,
UInt32 inStartFrame)
{
#if DEBUG_PRINT
printf("AUInstrumentBase::HandleControlChange ch %u ctlr: %u val: %u frm: %u\n", inChannel, inController, inValue, inStartFrame);
#endif
SynthGroupElement *gp = GetElForGroupID(inChannel);
if (gp)
{
gp->ChannelMessage(inController, inValue);
}
else
return kAudioUnitErr_InvalidElement;
switch (inController)
{
case kMidiController_Sustain :
if (inValue >= 64)
SendPedalEvent(inChannel, SynthEvent::kEventType_SustainOn, inStartFrame);
else
SendPedalEvent(inChannel, SynthEvent::kEventType_SustainOff, inStartFrame);
break;
case kMidiController_Sostenuto :
if (inValue >= 64)
SendPedalEvent(inChannel, SynthEvent::kEventType_SostenutoOn, inStartFrame);
else
SendPedalEvent(inChannel, SynthEvent::kEventType_SostenutoOff, inStartFrame);
break;
case kMidiController_OmniModeOff:
case kMidiController_OmniModeOn:
case kMidiController_MonoModeOn:
case kMidiController_MonoModeOff:
HandleAllSoundOff(inChannel);
break;
}
return noErr;
}
OSStatus AUInstrumentBase::HandlePitchWheel( UInt8 inChannel,
UInt8 inPitch1, // LSB
UInt8 inPitch2, // MSB
UInt32 inStartFrame)
{
SynthGroupElement *gp = GetElForGroupID(inChannel);
if (gp)
{
gp->ChannelMessage(kMidiMessage_PitchWheel, (inPitch2 << 7) | inPitch1);
return noErr;
}
else
return kAudioUnitErr_InvalidElement;
}
OSStatus AUInstrumentBase::HandleChannelPressure(UInt8 inChannel,
UInt8 inValue,
UInt32 inStartFrame)
{
SynthGroupElement *gp = GetElForGroupID(inChannel);
if (gp)
{
gp->ChannelMessage(kMidiMessage_ChannelPressure, inValue);
return noErr;
}
else
return kAudioUnitErr_InvalidElement;
}
OSStatus AUInstrumentBase::HandleProgramChange( UInt8 inChannel,
UInt8 inValue)
{
#if DEBUG_PRINT
printf("AUInstrumentBase::HandleProgramChange %u %u\n", inChannel, inValue);
#endif
SynthGroupElement *gp = GetElForGroupID(inChannel);
if (gp)
{
gp->ChannelMessage(kMidiMessage_ProgramChange, inValue);
return noErr;
}
else
return kAudioUnitErr_InvalidElement;
}
OSStatus AUInstrumentBase::HandlePolyPressure( UInt8 inChannel,
UInt8 inKey,
UInt8 inValue,
UInt32 inStartFrame)
{
SynthGroupElement *gp = GetElForGroupID(inChannel);
if (gp)
{
// Combine key and value into single argument. UGLY!
gp->ChannelMessage(kMidiMessage_PolyPressure, (inKey << 7) | inValue);
return noErr;
}
else
return kAudioUnitErr_InvalidElement;
}
OSStatus AUInstrumentBase::HandleResetAllControllers( UInt8 inChannel)
{
return SendPedalEvent (inChannel, SynthEvent::kEventType_ResetAllControllers, 0);
}
OSStatus AUInstrumentBase::HandleAllNotesOff( UInt8 inChannel)
{
return SendPedalEvent (inChannel, SynthEvent::kEventType_AllNotesOff, 0);
}
OSStatus AUInstrumentBase::HandleAllSoundOff( UInt8 inChannel)
{
return SendPedalEvent (inChannel, SynthEvent::kEventType_AllSoundOff, 0);
}
SynthNote* AUInstrumentBase::GetAFreeNote(UInt32 inFrame)
{
#if DEBUG_PRINT_NOTE
printf("AUInstrumentBase::GetAFreeNote: %lu available\n", mFreeNotes.Length());
#endif
SynthNote *note = mFreeNotes.mHead;
if (note)
{
mFreeNotes.RemoveNote(note);
return note;
}
return VoiceStealing(inFrame, true);
}
SynthNote* AUInstrumentBase::VoiceStealing(UInt32 inFrame, bool inKillIt)
{
#if DEBUG_PRINT_NOTE
printf("AUInstrumentBase::VoiceStealing\n");
#endif
// free list was empty so we need to kill a note.
UInt32 startState = inKillIt ? kNoteState_FastReleased : kNoteState_Released;
for (UInt32 i = startState; i <= startState; --i)
{
#if DEBUG_PRINT_NOTE
printf(" checking state %d...\n", i);
#endif
UInt32 numGroups = Groups().GetNumberOfElements();
for (UInt32 j = 0; j < numGroups; ++j)
{
SynthGroupElement *group = (SynthGroupElement*)Groups().GetElement(j);
#if DEBUG_PRINT_NOTE
printf("\tsteal group %d size %d\n", j, group->mNoteList[i].Length());
#endif
if (group->mNoteList[i].NotEmpty()) {
#if DEBUG_PRINT_NOTE
printf("\t-- not empty\n");
#endif
SynthNote *note = group->mNoteList[i].FindMostQuietNote();
if (inKillIt) {
#if DEBUG_PRINT_NOTE
printf("\t--=== KILL ===---\n");
#endif
note->Kill(inFrame);
group->mNoteList[i].RemoveNote(note);
if (i != kNoteState_FastReleased)
DecNumActiveNotes();
return note;
} else {
#if DEBUG_PRINT_NOTE
printf("\t--=== FAST RELEASE ===---\n");
#endif
group->mNoteList[i].RemoveNote(note);
note->FastRelease(inFrame);
group->mNoteList[kNoteState_FastReleased].AddNote(note);
DecNumActiveNotes(); // kNoteState_FastReleased counts as inactive for voice stealing purposes.
return NULL;
}
}
}
}
#if DEBUG_PRINT_NOTE
printf("no notes to steal????\n");
#endif
return NULL; // It should be impossible to get here. It means there were no notes to kill in any state.
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////
AUMonotimbralInstrumentBase::AUMonotimbralInstrumentBase(
AudioComponentInstance inInstance,
UInt32 numInputs,
UInt32 numOutputs,
UInt32 numGroups,
UInt32 numParts)
: AUInstrumentBase(inInstance, numInputs, numOutputs, numGroups, numParts)
{
}
OSStatus AUMonotimbralInstrumentBase::RealTimeStartNote(
SynthGroupElement *inGroup,
NoteInstanceID inNoteInstanceID,
UInt32 inOffsetSampleFrame,
const MusicDeviceNoteParams &inParams)
{
#if DEBUG_PRINT_RENDER
printf("AUMonotimbralInstrumentBase::RealTimeStartNote %d\n", inNoteInstanceID);
#endif
if (NumActiveNotes() + 1 > MaxActiveNotes())
{
VoiceStealing(inOffsetSampleFrame, false);
}
SynthNote *note = GetAFreeNote(inOffsetSampleFrame);
if (!note) return -1;
SynthPartElement *part = GetPartElement (0); // Only one part for monotimbral
IncNumActiveNotes();
inGroup->NoteOn(note, part, inNoteInstanceID, inOffsetSampleFrame, inParams);
return noErr;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////
OSStatus AUMultitimbralInstrumentBase::GetPropertyInfo(AudioUnitPropertyID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
UInt32 & outDataSize,
Boolean & outWritable)
{
OSStatus result = noErr;
switch (inID)
{
#if !TARGET_OS_IPHONE
case kMusicDeviceProperty_PartGroup:
if (inScope != kAudioUnitScope_Part) return kAudioUnitErr_InvalidScope;
outDataSize = sizeof(UInt32);
outWritable = true;
break;
#endif
default:
result = AUInstrumentBase::GetPropertyInfo (inID, inScope, inElement, outDataSize, outWritable);
}
return result;
}
OSStatus AUMultitimbralInstrumentBase::GetProperty( AudioUnitPropertyID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
void * outData)
{
OSStatus result = noErr;
switch (inID)
{
#if !TARGET_OS_IPHONE
case kMusicDeviceProperty_PartGroup:
if (inScope != kAudioUnitScope_Group) return kAudioUnitErr_InvalidScope;
// ??
return -1; //unimpl
break;
#endif
default:
result = AUInstrumentBase::GetProperty (inID, inScope, inElement, outData);
}
return result;
}
OSStatus AUMultitimbralInstrumentBase::SetProperty( AudioUnitPropertyID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
const void * inData,
UInt32 inDataSize)
{
OSStatus result = noErr;
switch (inID)
{
#if !TARGET_OS_IPHONE
case kMusicDeviceProperty_PartGroup:
if (inScope != kAudioUnitScope_Group) return kAudioUnitErr_InvalidScope;
// ??
return -1; //unimpl
break;
#endif
default:
result = MusicDeviceBase::SetProperty (inID, inScope, inElement, inData, inDataSize);
}
return result;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////