summaryrefslogtreecommitdiff
path: root/libs/appleutility/CoreAudio/AudioUnits/AUPublic/AUInstrumentBase
diff options
context:
space:
mode:
Diffstat (limited to 'libs/appleutility/CoreAudio/AudioUnits/AUPublic/AUInstrumentBase')
-rw-r--r--libs/appleutility/CoreAudio/AudioUnits/AUPublic/AUInstrumentBase/AUInstrumentBase.cpp843
-rw-r--r--libs/appleutility/CoreAudio/AudioUnits/AUPublic/AUInstrumentBase/AUInstrumentBase.h269
-rw-r--r--libs/appleutility/CoreAudio/AudioUnits/AUPublic/AUInstrumentBase/LockFreeFIFO.h168
-rw-r--r--libs/appleutility/CoreAudio/AudioUnits/AUPublic/AUInstrumentBase/MIDIControlHandler.h92
-rw-r--r--libs/appleutility/CoreAudio/AudioUnits/AUPublic/AUInstrumentBase/SynthElement.cpp419
-rw-r--r--libs/appleutility/CoreAudio/AudioUnits/AUPublic/AUInstrumentBase/SynthElement.h227
-rw-r--r--libs/appleutility/CoreAudio/AudioUnits/AUPublic/AUInstrumentBase/SynthEvent.h145
-rw-r--r--libs/appleutility/CoreAudio/AudioUnits/AUPublic/AUInstrumentBase/SynthNote.cpp140
-rw-r--r--libs/appleutility/CoreAudio/AudioUnits/AUPublic/AUInstrumentBase/SynthNote.h187
-rw-r--r--libs/appleutility/CoreAudio/AudioUnits/AUPublic/AUInstrumentBase/SynthNoteList.cpp93
-rw-r--r--libs/appleutility/CoreAudio/AudioUnits/AUPublic/AUInstrumentBase/SynthNoteList.h232
11 files changed, 2815 insertions, 0 deletions
diff --git a/libs/appleutility/CoreAudio/AudioUnits/AUPublic/AUInstrumentBase/AUInstrumentBase.cpp b/libs/appleutility/CoreAudio/AudioUnits/AUPublic/AUInstrumentBase/AUInstrumentBase.cpp
new file mode 100644
index 0000000000..1ce8b308b4
--- /dev/null
+++ b/libs/appleutility/CoreAudio/AudioUnits/AUPublic/AUInstrumentBase/AUInstrumentBase.cpp
@@ -0,0 +1,843 @@
+/*
+ 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;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
diff --git a/libs/appleutility/CoreAudio/AudioUnits/AUPublic/AUInstrumentBase/AUInstrumentBase.h b/libs/appleutility/CoreAudio/AudioUnits/AUPublic/AUInstrumentBase/AUInstrumentBase.h
new file mode 100644
index 0000000000..3ad7e03a66
--- /dev/null
+++ b/libs/appleutility/CoreAudio/AudioUnits/AUPublic/AUInstrumentBase/AUInstrumentBase.h
@@ -0,0 +1,269 @@
+/*
+ File: AUInstrumentBase.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 __AUInstrumentBase__
+#define __AUInstrumentBase__
+
+#include <vector>
+#include <stdexcept>
+#include <AudioUnit/AudioUnit.h>
+#include <CoreAudio/CoreAudio.h>
+#include <libkern/OSAtomic.h>
+#include "MusicDeviceBase.h"
+#include "LockFreeFIFO.h"
+#include "SynthEvent.h"
+#include "SynthNote.h"
+#include "SynthElement.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+typedef LockFreeFIFOWithFree<SynthEvent> SynthEventQueue;
+
+class AUInstrumentBase : public MusicDeviceBase
+{
+public:
+ AUInstrumentBase(
+ AudioComponentInstance inInstance,
+ UInt32 numInputs,
+ UInt32 numOutputs,
+ UInt32 numGroups = 16,
+ UInt32 numParts = 1);
+ virtual ~AUInstrumentBase();
+
+ virtual OSStatus Initialize();
+
+ /*! @method Parts */
+ AUScope & Parts() { return mPartScope; }
+
+ /*! @method GetPart */
+ AUElement * GetPart( AudioUnitElement inElement)
+ {
+ return mPartScope.SafeGetElement(inElement);
+ }
+
+ virtual AUScope * GetScopeExtended (AudioUnitScope inScope);
+
+ virtual AUElement * CreateElement( AudioUnitScope inScope,
+ AudioUnitElement inElement);
+
+ virtual void CreateExtendedElements();
+
+ virtual void Cleanup();
+
+ virtual OSStatus Reset( AudioUnitScope inScope,
+ AudioUnitElement inElement);
+
+ virtual bool ValidFormat( AudioUnitScope inScope,
+ AudioUnitElement inElement,
+ const CAStreamBasicDescription & inNewFormat);
+
+ virtual bool StreamFormatWritable( AudioUnitScope scope,
+ AudioUnitElement element);
+
+ virtual bool CanScheduleParameters() const { return false; }
+
+ virtual OSStatus Render( AudioUnitRenderActionFlags & ioActionFlags,
+ const AudioTimeStamp & inTimeStamp,
+ UInt32 inNumberFrames);
+
+ virtual OSStatus StartNote( MusicDeviceInstrumentID inInstrument,
+ MusicDeviceGroupID inGroupID,
+ NoteInstanceID * outNoteInstanceID,
+ UInt32 inOffsetSampleFrame,
+ const MusicDeviceNoteParams &inParams);
+
+ virtual OSStatus StopNote( MusicDeviceGroupID inGroupID,
+ NoteInstanceID inNoteInstanceID,
+ UInt32 inOffsetSampleFrame);
+
+ virtual OSStatus RealTimeStartNote( SynthGroupElement *inGroup,
+ NoteInstanceID inNoteInstanceID,
+ UInt32 inOffsetSampleFrame,
+ const MusicDeviceNoteParams &inParams);
+
+ virtual OSStatus RealTimeStopNote( MusicDeviceGroupID inGroupID,
+ NoteInstanceID inNoteInstanceID,
+ UInt32 inOffsetSampleFrame);
+
+ virtual OSStatus HandleControlChange( UInt8 inChannel,
+ UInt8 inController,
+ UInt8 inValue,
+ UInt32 inStartFrame);
+
+ virtual OSStatus HandlePitchWheel( UInt8 inChannel,
+ UInt8 inPitch1,
+ UInt8 inPitch2,
+ UInt32 inStartFrame);
+
+ virtual OSStatus HandleChannelPressure( UInt8 inChannel,
+ UInt8 inValue,
+ UInt32 inStartFrame);
+
+ virtual OSStatus HandleProgramChange( UInt8 inChannel,
+ UInt8 inValue);
+
+ virtual OSStatus HandlePolyPressure( UInt8 inChannel,
+ UInt8 inKey,
+ UInt8 inValue,
+ UInt32 inStartFrame);
+
+ virtual OSStatus HandleResetAllControllers( UInt8 inChannel);
+
+ virtual OSStatus HandleAllNotesOff( UInt8 inChannel);
+
+ virtual OSStatus HandleAllSoundOff( UInt8 inChannel);
+
+ SynthNote* GetNote(UInt32 inIndex)
+ {
+ if (!mNotes)
+ throw std::runtime_error("no notes");
+ return (SynthNote*)((char*)mNotes + inIndex * mNoteSize);
+ }
+
+ SynthNote* GetAFreeNote(UInt32 inFrame);
+ void AddFreeNote(SynthNote* inNote);
+
+ friend class SynthGroupElement;
+protected:
+
+ UInt32 NextNoteID() { return OSAtomicIncrement32((int32_t *)&mNoteIDCounter); }
+
+
+ // call SetNotes in your Initialize() method to give the base class your note structures and to set the maximum
+ // number of active notes. inNoteData should be an array of size inMaxActiveNotes.
+ void SetNotes(UInt32 inNumNotes, UInt32 inMaxActiveNotes, SynthNote* inNotes, UInt32 inNoteSize);
+
+ void PerformEvents( const AudioTimeStamp & inTimeStamp);
+ OSStatus SendPedalEvent(MusicDeviceGroupID inGroupID, UInt32 inEventType, UInt32 inOffsetSampleFrame);
+ virtual SynthNote* VoiceStealing(UInt32 inFrame, bool inKillIt);
+ UInt32 MaxActiveNotes() const { return mMaxActiveNotes; }
+ UInt32 NumActiveNotes() const { return mNumActiveNotes; }
+ void IncNumActiveNotes() { ++mNumActiveNotes; }
+ void DecNumActiveNotes() { --mNumActiveNotes; }
+ UInt32 CountActiveNotes();
+
+ SynthPartElement * GetPartElement (AudioUnitElement inPartElement);
+
+ // this call throws if there's no assigned element for the group ID
+ virtual SynthGroupElement * GetElForGroupID (MusicDeviceGroupID inGroupID);
+ virtual SynthGroupElement * GetElForNoteID (NoteInstanceID inNoteID);
+
+ SInt64 mAbsoluteSampleFrame;
+
+
+private:
+
+ SInt32 mNoteIDCounter;
+
+ SynthEventQueue mEventQueue;
+
+ UInt32 mNumNotes;
+ UInt32 mNumActiveNotes;
+ UInt32 mMaxActiveNotes;
+ SynthNote* mNotes;
+ SynthNoteList mFreeNotes;
+ UInt32 mNoteSize;
+
+ AUScope mPartScope;
+ const UInt32 mInitNumPartEls;
+};
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+class AUMonotimbralInstrumentBase : public AUInstrumentBase
+{
+public:
+ AUMonotimbralInstrumentBase(
+ AudioComponentInstance inInstance,
+ UInt32 numInputs,
+ UInt32 numOutputs,
+ UInt32 numGroups = 16,
+ UInt32 numParts = 1);
+
+ virtual OSStatus RealTimeStartNote( SynthGroupElement *inGroup,
+ NoteInstanceID inNoteInstanceID,
+ UInt32 inOffsetSampleFrame,
+ const MusicDeviceNoteParams &inParams);
+};
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+// this is a work in progress! The mono-timbral one is finished though!
+class AUMultitimbralInstrumentBase : public AUInstrumentBase
+{
+public:
+ AUMultitimbralInstrumentBase(
+ AudioComponentInstance inInstance,
+ UInt32 numInputs,
+ UInt32 numOutputs,
+ UInt32 numGroups,
+ UInt32 numParts);
+
+ virtual OSStatus GetPropertyInfo( AudioUnitPropertyID inID,
+ AudioUnitScope inScope,
+ AudioUnitElement inElement,
+ UInt32 & outDataSize,
+ Boolean & outWritable);
+
+ virtual OSStatus GetProperty( AudioUnitPropertyID inID,
+ AudioUnitScope inScope,
+ AudioUnitElement inElement,
+ void * outData);
+
+ virtual OSStatus SetProperty( AudioUnitPropertyID inID,
+ AudioUnitScope inScope,
+ AudioUnitElement inElement,
+ const void * inData,
+ UInt32 inDataSize);
+
+private:
+
+};
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+#endif
+
diff --git a/libs/appleutility/CoreAudio/AudioUnits/AUPublic/AUInstrumentBase/LockFreeFIFO.h b/libs/appleutility/CoreAudio/AudioUnits/AUPublic/AUInstrumentBase/LockFreeFIFO.h
new file mode 100644
index 0000000000..ea6c4c26e1
--- /dev/null
+++ b/libs/appleutility/CoreAudio/AudioUnits/AUPublic/AUInstrumentBase/LockFreeFIFO.h
@@ -0,0 +1,168 @@
+/*
+ File: LockFreeFIFO.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.
+
+*/
+#include <libkern/OSAtomic.h>
+
+template <class ITEM>
+class LockFreeFIFOWithFree
+{
+ LockFreeFIFOWithFree(); // private, unimplemented.
+public:
+ LockFreeFIFOWithFree(UInt32 inMaxSize)
+ : mReadIndex(0), mWriteIndex(0), mFreeIndex(0)
+ {
+ //assert(IsPowerOfTwo(inMaxSize));
+ mItems = new ITEM[inMaxSize];
+ mMask = inMaxSize - 1;
+ }
+
+ ~LockFreeFIFOWithFree()
+ {
+ delete [] mItems;
+ }
+
+
+ void Reset()
+ {
+ FreeItems();
+ mReadIndex = 0;
+ mWriteIndex = 0;
+ mFreeIndex = 0;
+ }
+
+ ITEM* WriteItem()
+ {
+ //printf("WriteItem %d %d\n", mReadIndex, mWriteIndex);
+ FreeItems(); // free items on the write thread.
+ int32_t nextWriteIndex = (mWriteIndex + 1) & mMask;
+ if (nextWriteIndex == mFreeIndex) return NULL;
+ return &mItems[mWriteIndex];
+ }
+
+ ITEM* ReadItem()
+ {
+ //printf("ReadItem %d %d\n", mReadIndex, mWriteIndex);
+ if (mReadIndex == mWriteIndex) return NULL;
+ return &mItems[mReadIndex];
+ }
+ void AdvanceWritePtr() { OSAtomicCompareAndSwap32(mWriteIndex, (mWriteIndex + 1) & mMask, &mWriteIndex); }
+ void AdvanceReadPtr() { OSAtomicCompareAndSwap32(mReadIndex, (mReadIndex + 1) & mMask, &mReadIndex); }
+private:
+ ITEM* FreeItem()
+ {
+ if (mFreeIndex == mReadIndex) return NULL;
+ return &mItems[mFreeIndex];
+ }
+ void AdvanceFreePtr() { OSAtomicCompareAndSwap32(mFreeIndex, (mFreeIndex + 1) & mMask, &mFreeIndex); }
+
+ void FreeItems()
+ {
+ ITEM* item;
+ while ((item = FreeItem()) != NULL)
+ {
+ item->Free();
+ AdvanceFreePtr();
+ }
+ }
+
+ volatile int32_t mReadIndex, mWriteIndex, mFreeIndex;
+ int32_t mMask;
+ ITEM *mItems;
+};
+
+
+
+// Same as above but no free.
+
+template <class ITEM>
+class LockFreeFIFO
+{
+ LockFreeFIFO(); // private, unimplemented.
+public:
+ LockFreeFIFO(UInt32 inMaxSize)
+ : mReadIndex(0), mWriteIndex(0)
+ {
+ //assert(IsPowerOfTwo(inMaxSize));
+ mItems = new ITEM[inMaxSize];
+ mMask = inMaxSize - 1;
+ }
+
+ ~LockFreeFIFO()
+ {
+ delete [] mItems;
+ }
+
+ void Reset()
+ {
+ mReadIndex = 0;
+ mWriteIndex = 0;
+ }
+
+ ITEM* WriteItem()
+ {
+ int32_t nextWriteIndex = (mWriteIndex + 1) & mMask;
+ if (nextWriteIndex == mReadIndex) return NULL;
+ return &mItems[mWriteIndex];
+ }
+
+ ITEM* ReadItem()
+ {
+ if (mReadIndex == mWriteIndex) return NULL;
+ return &mItems[mReadIndex];
+ }
+
+ // the CompareAndSwap will always succeed. We use CompareAndSwap because it calls the PowerPC sync instruction,
+ // plus any processor bug workarounds for various CPUs.
+ void AdvanceWritePtr() { OSAtomicCompareAndSwap32(mWriteIndex, (mWriteIndex + 1) & mMask, &mWriteIndex); }
+ void AdvanceReadPtr() { OSAtomicCompareAndSwap32(mReadIndex, (mReadIndex + 1) & mMask, &mReadIndex); }
+
+private:
+
+ volatile int32_t mReadIndex, mWriteIndex;
+ int32_t mMask;
+ ITEM *mItems;
+};
+
diff --git a/libs/appleutility/CoreAudio/AudioUnits/AUPublic/AUInstrumentBase/MIDIControlHandler.h b/libs/appleutility/CoreAudio/AudioUnits/AUPublic/AUInstrumentBase/MIDIControlHandler.h
new file mode 100644
index 0000000000..0f8003fcd5
--- /dev/null
+++ b/libs/appleutility/CoreAudio/AudioUnits/AUPublic/AUInstrumentBase/MIDIControlHandler.h
@@ -0,0 +1,92 @@
+/*
+ File: MIDIControlHandler.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 __MIDICONTROLHANDLER_H__
+#define __MIDICONTROLHANDLER_H__
+
+#include <CoreAudio/CoreAudio.h>
+
+/*! Abstract interface base class for classes which handle all incoming MIDI data */
+
+class MIDIControlHandler
+{
+public:
+ virtual ~MIDIControlHandler() {}
+ virtual void Reset() = 0; //! Restore all state to defaults
+ virtual bool SetProgramChange(UInt16 inProgram) = 0;
+ virtual bool SetPitchWheel(UInt16 inValue) = 0;
+ virtual bool SetChannelPressure(UInt8 inValue) = 0;
+ virtual bool SetPolyPressure(UInt8 inKey, UInt8 inValue) = 0;
+ virtual bool SetController(UInt8 inControllerNumber, UInt8 inValue) = 0;
+ virtual bool SetSysex(void *inSysexMsg) = 0;
+
+ virtual float GetPitchBend() const = 0;
+
+ /*! Default controller values. These represent MSB values unless indicated in the name */
+
+ enum
+ {
+ kDefault_Midpoint = 0x40, //! Used for all center-null-point controllers
+ kDefault_Volume = 100,
+ kDefault_Pan = kDefault_Midpoint,
+ kDefault_ModWheel = 0,
+ kDefault_Pitch = kDefault_Midpoint,
+ kDefault_Expression = 0x7f,
+ kDefault_ChannelPressure = 0,
+ kDefault_ReverbSend = 40,
+ kDefault_ChorusSend = 0,
+
+ kDefault_RPN_LSB = 0x7f,
+ kDefault_RPN_MSB = 0x7f,
+ kDefault_PitchBendRange = 2,
+ kDefault_FineTuning = kDefault_Midpoint,
+ kDefault_CoarseTuning = kDefault_Midpoint,
+ kDefault_ModDepthRange = 0,
+ kDefault_ModDepthRangeLSB = kDefault_Midpoint
+ };
+};
+
+#endif // __MIDICONTROLHANDLER_H__
diff --git a/libs/appleutility/CoreAudio/AudioUnits/AUPublic/AUInstrumentBase/SynthElement.cpp b/libs/appleutility/CoreAudio/AudioUnits/AUPublic/AUInstrumentBase/SynthElement.cpp
new file mode 100644
index 0000000000..fd329f84e8
--- /dev/null
+++ b/libs/appleutility/CoreAudio/AudioUnits/AUPublic/AUInstrumentBase/SynthElement.cpp
@@ -0,0 +1,419 @@
+/*
+ File: SynthElement.cpp
+ Abstract: SynthElement.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 "SynthElement.h"
+#include "AUInstrumentBase.h"
+#include "AUMIDIDefs.h"
+
+#undef DEBUG_PRINT
+#define DEBUG_PRINT 0
+#define DEBUG_PRINT_NOTE 0
+#define DEBUG_PRINT_RENDER 0
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////
+MidiControls::MidiControls()
+{
+ Reset();
+}
+
+void MidiControls::Reset()
+{
+ memset(mControls, 0, sizeof(mControls));
+ memset(mPolyPressure, 0, sizeof(mPolyPressure));
+ mMonoPressure = 0;
+ mProgramChange = 0;
+ mPitchBend = 0;
+ mActiveRPN = 0;
+ mActiveNRPN = 0;
+ mActiveRPValue = 0;
+ mActiveNRPValue = 0;
+ mControls[kMidiController_Pan] = 64;
+ mControls[kMidiController_Expression] = 127;
+ mPitchBendDepth = 24 << 7;
+ mFPitchBendDepth = 24.0f;
+ mFPitchBend = 0.0f;
+}
+
+
+SynthElement::SynthElement(AUInstrumentBase *audioUnit, UInt32 inElement)
+ : AUElement(audioUnit), mIndex(inElement)
+{
+}
+
+SynthElement::~SynthElement()
+{
+}
+
+SynthGroupElement::SynthGroupElement(AUInstrumentBase *audioUnit, UInt32 inElement, MIDIControlHandler *inHandler)
+ : SynthElement(audioUnit, inElement),
+ mCurrentAbsoluteFrame(-1),
+ mMidiControlHandler(inHandler),
+ mSustainIsOn(false), mSostenutoIsOn(false), mOutputBus(0), mGroupID(kUnassignedGroup)
+{
+ for (UInt32 i=0; i<kNumberOfSoundingNoteStates; ++i)
+ mNoteList[i].mState = (SynthNoteState) i;
+}
+
+SynthGroupElement::~SynthGroupElement()
+{
+ delete mMidiControlHandler;
+}
+
+void SynthGroupElement::SetGroupID (MusicDeviceGroupID inGroup)
+{
+ // can't re-assign a group once its been assigned
+ if (mGroupID != kUnassignedGroup) throw static_cast<OSStatus>(kAudioUnitErr_InvalidElement);
+ mGroupID = inGroup;
+}
+
+void SynthGroupElement::Reset()
+{
+#if DEBUG_PRINT
+ printf("SynthGroupElement::Reset\n");
+#endif
+ mMidiControlHandler->Reset();
+ for (UInt32 i=0; i<kNumberOfSoundingNoteStates; ++i)
+ mNoteList[i].Empty();
+}
+
+SynthPartElement::SynthPartElement(AUInstrumentBase *audioUnit, UInt32 inElement)
+ : SynthElement(audioUnit, inElement)
+{
+}
+
+// Return the SynthNote with the given inNoteID, if found. If unreleasedOnly is true, only look for
+// attacked and sostenutoed notes, otherwise search all states. Return state of found note via outNoteState.
+
+SynthNote *SynthGroupElement::GetNote(NoteInstanceID inNoteID, bool unreleasedOnly, UInt32 *outNoteState)
+{
+#if DEBUG_PRINT_RENDER
+ printf("SynthGroupElement::GetNote %d, unreleased = %d\n", inNoteID, unreleasedOnly);
+#endif
+ const UInt32 lastNoteState = unreleasedOnly ?
+ (mSostenutoIsOn ? kNoteState_Sostenutoed : kNoteState_Attacked)
+ : kNoteState_Released;
+ SynthNote *note = NULL;
+ // Search for notes in each successive state
+ for (UInt32 noteState = kNoteState_Attacked; noteState <= lastNoteState; ++noteState)
+ {
+ if (outNoteState) *outNoteState = noteState; // even if we find nothing
+ note = mNoteList[noteState].mHead;
+ while (note && note->mNoteID != inNoteID)
+ {
+#if DEBUG_PRINT_RENDER
+ printf(" checking %p id: %d\n", note, note->mNoteID);
+#endif
+ note = note->mNext;
+ }
+ if (note)
+ {
+#if DEBUG_PRINT_RENDER
+ printf(" found %p\n", note);
+#endif
+ break;
+ }
+ }
+ return note;
+}
+
+void SynthGroupElement::NoteOn(SynthNote *note,
+ SynthPartElement *part,
+ NoteInstanceID inNoteID,
+ UInt32 inOffsetSampleFrame,
+ const MusicDeviceNoteParams &inParams)
+{
+#if DEBUG_PRINT_NOTE
+ printf("SynthGroupElement::NoteOn %d\n", inNoteID);
+#endif
+ // TODO: CONSIDER FIXING this to not need to initialize mCurrentAbsoluteFrame to -1.
+ UInt64 absoluteFrame = (mCurrentAbsoluteFrame == -1) ? inOffsetSampleFrame : mCurrentAbsoluteFrame + inOffsetSampleFrame;
+ if (note->AttackNote(part, this, inNoteID, absoluteFrame, inOffsetSampleFrame, inParams)) {
+ mNoteList[kNoteState_Attacked].AddNote(note);
+ }
+}
+
+void SynthGroupElement::NoteOff(NoteInstanceID inNoteID, UInt32 inFrame)
+{
+#if DEBUG_PRINT_NOTE
+ printf("SynthGroupElement::NoteOff %d\n", inNoteID);
+#endif
+ UInt32 noteState = kNoteState_Attacked;
+ SynthNote *note = GetNote(inNoteID, true, &noteState); // asking for unreleased only
+ if (note)
+ {
+#if DEBUG_PRINT_NOTE
+ printf(" old note state: %d\n", note->mState);
+#endif
+ if (noteState == kNoteState_Attacked)
+ {
+ mNoteList[noteState].RemoveNote(note);
+ if (mSustainIsOn) {
+ mNoteList[kNoteState_ReleasedButSustained].AddNote(note);
+ } else {
+ note->Release(inFrame);
+ mNoteList[kNoteState_Released].AddNote(note);
+ }
+#if DEBUG_PRINT_NOTE
+ printf(" new note state: %d\n", note->mState);
+#endif
+ }
+ else /* if (noteState == kNoteState_Sostenutoed) */
+ {
+ mNoteList[kNoteState_Sostenutoed].RemoveNote(note);
+ mNoteList[kNoteState_ReleasedButSostenutoed].AddNote(note);
+ }
+ }
+}
+
+void SynthGroupElement::NoteEnded(SynthNote *inNote, UInt32 inFrame)
+{
+#if DEBUG_PRINT_NOTE
+ printf("SynthGroupElement::NoteEnded: id %d state %d\n", inNote->mNoteID, inNote->mState);
+#endif
+ if (inNote->IsSounding()) {
+ SynthNoteList *list = &mNoteList[inNote->GetState()];
+ list->RemoveNote(inNote);
+ }
+
+ GetAUInstrument()->AddFreeNote(inNote);
+}
+
+void SynthGroupElement::NoteFastReleased(SynthNote *inNote)
+{
+#if DEBUG_PRINT_NOTE
+ printf("SynthGroupElement::NoteFastReleased id %d state %d\n", inNote->mNoteID, inNote->mState);
+#endif
+ if (inNote->IsActive()) {
+ mNoteList[inNote->GetState()].RemoveNote(inNote);
+ GetAUInstrument()->DecNumActiveNotes();
+ mNoteList[kNoteState_FastReleased].AddNote(inNote);
+ }
+ else {
+ Assert(true, "ASSERT FAILED: Attempting to fast-release non-active note");
+ }
+}
+
+bool SynthGroupElement::ChannelMessage(UInt16 controllerID, UInt16 inValue)
+{
+ bool handled = true;
+#if DEBUG_PRINT
+ printf("SynthGroupElement::ChannelMessage(0x%x, %u)\n", controllerID, inValue);
+#endif
+ // Sustain and sostenuto are "pedal events", and are handled during render cycle
+ if (controllerID <= kMidiController_RPN_MSB && controllerID != kMidiController_Sustain && controllerID != kMidiController_Sostenuto)
+ handled = mMidiControlHandler->SetController(controllerID, UInt8(inValue));
+ else
+ {
+ switch (controllerID)
+ {
+ case kMidiMessage_ProgramChange:
+ handled = mMidiControlHandler->SetProgramChange(inValue);
+ break;
+ case kMidiMessage_PitchWheel:
+ handled = mMidiControlHandler->SetPitchWheel(inValue);
+ break;
+ case kMidiMessage_ChannelPressure:
+#if DEBUG_PRINT
+ printf("SynthGroupElement::ChannelMessage: Channel Pressure %u\n", inValue);
+#endif
+ handled = mMidiControlHandler->SetChannelPressure(UInt8(inValue));
+ break;
+ case kMidiMessage_PolyPressure:
+ { UInt8 inKey = inValue >> 7;
+ UInt8 val = inValue & 0x7f;
+ handled = mMidiControlHandler->SetPolyPressure(inKey, val);
+ break;
+ }
+ default:
+ handled = false;
+ break;
+ }
+ }
+ return handled;
+}
+
+void SynthGroupElement::SostenutoOn(UInt32 inFrame)
+{
+#if DEBUG_PRINT
+ printf("SynthGroupElement::SostenutoOn\n");
+#endif
+ if (!mSostenutoIsOn) {
+ mMidiControlHandler->SetController(kMidiController_Sostenuto, 127);
+ mSostenutoIsOn = true;
+ mNoteList[kNoteState_Sostenutoed].TransferAllFrom(&mNoteList[kNoteState_Attacked], inFrame);
+ }
+}
+
+void SynthGroupElement::SostenutoOff(UInt32 inFrame)
+{
+#if DEBUG_PRINT
+ printf("SynthGroupElement::SostenutoOff\n");
+#endif
+ if (mSostenutoIsOn) {
+ mMidiControlHandler->SetController(kMidiController_Sostenuto, 0);
+ mSostenutoIsOn = false;
+ mNoteList[kNoteState_Attacked].TransferAllFrom(&mNoteList[kNoteState_Sostenutoed], inFrame);
+ if (mSustainIsOn)
+ mNoteList[kNoteState_ReleasedButSustained].TransferAllFrom(&mNoteList[kNoteState_ReleasedButSostenutoed], inFrame);
+ else
+ mNoteList[kNoteState_Released].TransferAllFrom(&mNoteList[kNoteState_ReleasedButSostenutoed], inFrame);
+ }
+}
+
+
+void SynthGroupElement::SustainOn(UInt32 inFrame)
+{
+#if DEBUG_PRINT
+// printf("SynthGroupElement::SustainOn\n");
+#endif
+ if (!mSustainIsOn) {
+ mMidiControlHandler->SetController(kMidiController_Sustain, 127);
+ mSustainIsOn = true;
+ }
+}
+
+void SynthGroupElement::SustainOff(UInt32 inFrame)
+{
+#if DEBUG_PRINT
+// printf("SynthGroupElement::SustainOff\n");
+#endif
+ if (mSustainIsOn) {
+ mMidiControlHandler->SetController(kMidiController_Sustain, 0);
+ mSustainIsOn = false;
+
+ mNoteList[kNoteState_Released].TransferAllFrom(&mNoteList[kNoteState_ReleasedButSustained], inFrame);
+ }
+}
+
+void SynthGroupElement::AllNotesOff(UInt32 inFrame)
+{
+#if DEBUG_PRINT
+ printf("SynthGroupElement::AllNotesOff\n");
+#endif
+ SynthNote *note;
+ for (UInt32 i=0 ; i<=kNoteState_Sostenutoed; ++i)
+ {
+ UInt32 newState = (i == kNoteState_Attacked) ?
+ kNoteState_Released : kNoteState_ReleasedButSostenutoed;
+ note = mNoteList[i].mHead;
+ while (note)
+ {
+ SynthNote *nextNote = note->mNext;
+
+ mNoteList[i].RemoveNote(note);
+ note->Release(inFrame);
+ mNoteList[newState].AddNote(note);
+
+ note = nextNote;
+ }
+ }
+}
+
+void SynthGroupElement::AllSoundOff(UInt32 inFrame)
+{
+#if DEBUG_PRINT
+ printf("SynthGroupElement::AllSoundOff\n");
+#endif
+ SynthNote *note;
+
+ for (UInt32 i=0 ; i<kNumberOfActiveNoteStates; ++i)
+ {
+ note = mNoteList[i].mHead;
+ while (note)
+ {
+ SynthNote *nextNote = note->mNext;
+
+ mNoteList[i].RemoveNote(note);
+ note->FastRelease(inFrame);
+ mNoteList[kNoteState_FastReleased].AddNote(note);
+ GetAUInstrument()->DecNumActiveNotes();
+ note = nextNote;
+ }
+ }
+}
+
+void SynthGroupElement::ResetAllControllers(UInt32 inFrame)
+{
+#if DEBUG_PRINT
+ printf("SynthGroupElement::ResetAllControllers\n");
+#endif
+ mMidiControlHandler->Reset();
+}
+
+OSStatus SynthGroupElement::Render(SInt64 inAbsoluteSampleFrame, UInt32 inNumberFrames, AUScope &outputs)
+{
+ // Avoid duplicate calls at same sample offset
+ if (inAbsoluteSampleFrame != mCurrentAbsoluteFrame)
+ {
+ mCurrentAbsoluteFrame = inAbsoluteSampleFrame;
+ AudioBufferList* buffArray[16];
+ UInt32 numOutputs = outputs.GetNumberOfElements();
+ for (UInt32 outBus = 0; outBus < numOutputs && outBus < 16; ++outBus)
+ {
+ buffArray[outBus] = &GetAudioUnit()->GetOutput(outBus)->GetBufferList();
+ }
+
+ for (UInt32 i=0 ; i<kNumberOfSoundingNoteStates; ++i)
+ {
+ SynthNote *note = mNoteList[i].mHead;
+ while (note)
+ {
+#if DEBUG_PRINT_RENDER
+ printf("SynthGroupElement::Render: state %d, note %p\n", i, note);
+#endif
+ SynthNote *nextNote = note->mNext;
+
+ OSStatus err = note->Render(inAbsoluteSampleFrame, inNumberFrames, buffArray, numOutputs);
+ if (err) return err;
+
+ note = nextNote;
+ }
+ }
+ }
+ return noErr;
+}
+
+
diff --git a/libs/appleutility/CoreAudio/AudioUnits/AUPublic/AUInstrumentBase/SynthElement.h b/libs/appleutility/CoreAudio/AudioUnits/AUPublic/AUInstrumentBase/SynthElement.h
new file mode 100644
index 0000000000..4ca3643106
--- /dev/null
+++ b/libs/appleutility/CoreAudio/AudioUnits/AUPublic/AUInstrumentBase/SynthElement.h
@@ -0,0 +1,227 @@
+/*
+ File: SynthElement.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 __SynthElement__
+#define __SynthElement__
+
+#include <AudioUnit/AudioUnit.h>
+#include "MusicDeviceBase.h"
+#include "SynthNoteList.h"
+#include "MIDIControlHandler.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////
+class AUInstrumentBase;
+
+class SynthElement : public AUElement
+{
+public:
+ SynthElement(AUInstrumentBase *audioUnit, UInt32 inElement);
+ virtual ~SynthElement();
+
+ UInt32 GetIndex() const { return mIndex; }
+
+ AUInstrumentBase* GetAUInstrument() { return (AUInstrumentBase*)GetAudioUnit(); }
+
+private:
+ UInt32 mIndex;
+};
+
+class MidiControls : public MIDIControlHandler
+{
+ enum { kMaxControls = 128 };
+public:
+ MidiControls();
+ virtual ~MidiControls() {}
+ virtual void Reset();
+ virtual bool SetProgramChange(UInt16 inProgram) { mProgramChange = inProgram; return true; }
+ virtual bool SetPitchWheel(UInt16 inValue) {
+ mPitchBend = inValue;
+ mFPitchBend = (float)(((SInt16)mPitchBend - 8192) / 8192.);
+ return true;
+ }
+ virtual bool SetChannelPressure(UInt8 inValue) { mMonoPressure = inValue; return true; }
+ virtual bool SetPolyPressure(UInt8 inKey, UInt8 inValue) {
+ mPolyPressure[inKey] = inValue;
+ return true;
+ }
+ virtual bool SetController(UInt8 inControllerNumber, UInt8 inValue) {
+ if (inControllerNumber < kMaxControls) {
+ mControls[inControllerNumber] = inValue;
+ return true;
+ }
+ return false;
+ }
+ virtual bool SetSysex(void *inSysexMsg) { return false; }
+
+ virtual float GetPitchBend() const { return mFPitchBend * mFPitchBendDepth; }
+
+ SInt16 GetHiResControl(UInt32 inIndex) const
+ {
+ return ((mControls[inIndex] & 127) << 7) | (mControls[inIndex + 32] & 127);
+ }
+
+ float GetControl(UInt32 inIndex) const
+ {
+ if (inIndex < 32) {
+ return (float)(mControls[inIndex] + (mControls[inIndex + 32] / 127.));
+ } else {
+ return (float)mControls[inIndex];
+ }
+ }
+
+
+private:
+
+ UInt8 mControls[128];
+ UInt8 mPolyPressure[128];
+ UInt8 mMonoPressure;
+ UInt8 mProgramChange;
+ UInt16 mPitchBend;
+ UInt16 mActiveRPN;
+ UInt16 mActiveNRPN;
+ UInt16 mActiveRPValue;
+ UInt16 mActiveNRPValue;
+
+ UInt16 mPitchBendDepth;
+ float mFPitchBendDepth;
+ float mFPitchBend;
+
+ void SetHiResControl(UInt32 inIndex, UInt8 inMSB, UInt8 inLSB)
+ {
+ mControls[inIndex] = inMSB;
+ mControls[inIndex + 32] = inLSB;
+ }
+
+};
+
+
+class SynthGroupElement : public SynthElement
+{
+public:
+ enum {
+ kUnassignedGroup = 0xFFFFFFFF
+ };
+
+ SynthGroupElement(AUInstrumentBase *audioUnit, UInt32 inElement, MIDIControlHandler *inHandler);
+ virtual ~SynthGroupElement();
+
+ virtual void NoteOn(SynthNote *note, SynthPartElement *part, NoteInstanceID inNoteID, UInt32 inOffsetSampleFrame, const MusicDeviceNoteParams &inParams);
+ virtual void NoteOff(NoteInstanceID inNoteID, UInt32 inOffsetSampleFrame);
+ void SustainOn(UInt32 inFrame);
+ void SustainOff(UInt32 inFrame);
+ void SostenutoOn(UInt32 inFrame);
+ void SostenutoOff(UInt32 inFrame);
+
+ void NoteEnded(SynthNote *inNote, UInt32 inFrame);
+ void NoteFastReleased(SynthNote *inNote);
+
+ virtual bool ChannelMessage(UInt16 controlID, UInt16 controlValue);
+ virtual void AllNotesOff(UInt32 inFrame);
+ virtual void AllSoundOff(UInt32 inFrame);
+ void ResetAllControllers(UInt32 inFrame);
+
+ SynthNote * GetNote(NoteInstanceID inNoteID, bool unreleasedOnly=false, UInt32 *outNoteState=NULL);
+
+ void Reset();
+
+ virtual OSStatus Render(SInt64 inAbsoluteSampleFrame, UInt32 inNumberFrames, AUScope &outputs);
+
+ float GetPitchBend() const { return mMidiControlHandler->GetPitchBend(); }
+ SInt64 GetCurrentAbsoluteFrame() const { return mCurrentAbsoluteFrame; }
+
+ MusicDeviceGroupID GroupID () const { return mGroupID; }
+ virtual void SetGroupID (MusicDeviceGroupID inGroup);
+
+ MIDIControlHandler * GetMIDIControlHandler() const { return mMidiControlHandler; }
+
+protected:
+ SInt64 mCurrentAbsoluteFrame;
+ SynthNoteList mNoteList[kNumberOfSoundingNoteStates];
+ MIDIControlHandler *mMidiControlHandler;
+
+private:
+ friend class AUInstrumentBase;
+ friend class AUMonotimbralInstrumentBase;
+ friend class AUMultitimbralInstrumentBase;
+
+ bool mSustainIsOn;
+ bool mSostenutoIsOn;
+ UInt32 mOutputBus;
+ MusicDeviceGroupID mGroupID;
+};
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////
+struct SynthKeyZone
+{
+ UInt8 mLoNote;
+ UInt8 mHiNote;
+ UInt8 mLoVelocity;
+ UInt8 mHiVelocity;
+};
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+const UInt32 kUnlimitedPolyphony = 0xFFFFFFFF;
+
+class SynthPartElement : public SynthElement
+{
+public:
+ SynthPartElement(AUInstrumentBase *audioUnit, UInt32 inElement);
+
+ UInt32 GetGroupIndex() const { return mGroupIndex; }
+ bool InRange(Float32 inNote, Float32 inVelocity);
+
+ UInt32 GetMaxPolyphony() const { return mMaxPolyphony; }
+ void SetMaxPolyphony(UInt32 inMaxPolyphony) { mMaxPolyphony = inMaxPolyphony; }
+
+private:
+ UInt32 mGroupIndex;
+ UInt32 mPatchIndex;
+ UInt32 mMaxPolyphony;
+ SynthKeyZone mKeyZone;
+};
+
+#endif
diff --git a/libs/appleutility/CoreAudio/AudioUnits/AUPublic/AUInstrumentBase/SynthEvent.h b/libs/appleutility/CoreAudio/AudioUnits/AUPublic/AUInstrumentBase/SynthEvent.h
new file mode 100644
index 0000000000..9c27aee04f
--- /dev/null
+++ b/libs/appleutility/CoreAudio/AudioUnits/AUPublic/AUInstrumentBase/SynthEvent.h
@@ -0,0 +1,145 @@
+/*
+ File: SynthEvent.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.
+
+*/
+/* You can either fill in code here or remove this and create or add new files. */
+
+#ifndef __SynthEvent__
+#define __SynthEvent__
+
+#include <AudioUnit/AudioUnit.h>
+#include <CoreAudio/CoreAudio.h>
+#include "MusicDeviceBase.h"
+#include <stdexcept>
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+class SynthEvent
+{
+public:
+ enum {
+ kEventType_NoteOn = 1,
+ kEventType_NoteOff = 2,
+ kEventType_SustainOn = 3,
+ kEventType_SustainOff = 4,
+ kEventType_SostenutoOn = 5,
+ kEventType_SostenutoOff = 6,
+ kEventType_AllNotesOff = 7,
+ kEventType_AllSoundOff = 8,
+ kEventType_ResetAllControllers = 9
+ };
+
+
+ SynthEvent() {}
+ ~SynthEvent() {}
+
+ void Set(
+ UInt32 inEventType,
+ MusicDeviceGroupID inGroupID,
+ NoteInstanceID inNoteID,
+ UInt32 inOffsetSampleFrame,
+ const MusicDeviceNoteParams* inNoteParams
+ )
+ {
+ mEventType = inEventType;
+ mGroupID = inGroupID;
+ mNoteID = inNoteID;
+ mOffsetSampleFrame = inOffsetSampleFrame;
+
+ if (inNoteParams)
+ {
+ UInt32 paramSize = offsetof(MusicDeviceNoteParams, mControls) + (inNoteParams->argCount-2)*sizeof(NoteParamsControlValue);
+ mNoteParams = inNoteParams->argCount > 3
+ ? (MusicDeviceNoteParams*)malloc(paramSize)
+ : &mSmallNoteParams;
+ memcpy(mNoteParams, inNoteParams, paramSize);
+ }
+ else
+ mNoteParams = NULL;
+ }
+
+
+ void Free()
+ {
+ if (mNoteParams)
+ {
+ if (mNoteParams->argCount > 3)
+ free(mNoteParams);
+ mNoteParams = NULL;
+ }
+ }
+
+ UInt32 GetEventType() const { return mEventType; }
+ MusicDeviceGroupID GetGroupID() const { return mGroupID; }
+ NoteInstanceID GetNoteID() const { return mNoteID; }
+ UInt32 GetOffsetSampleFrame() const { return mOffsetSampleFrame; }
+
+ MusicDeviceNoteParams* GetParams() const { return mNoteParams; }
+
+ UInt32 GetArgCount() const { return mNoteParams->argCount; }
+ UInt32 NumberParameters() const { return mNoteParams->argCount - 2; }
+
+ Float32 GetNote() const { return mNoteParams->mPitch; }
+ Float32 GetVelocity() const { return mNoteParams->mVelocity; }
+
+ NoteParamsControlValue GetParameter(UInt32 inIndex) const
+ {
+ if (inIndex >= NumberParameters())
+ throw std::runtime_error("index out of range");
+ return mNoteParams->mControls[inIndex];
+ }
+
+private:
+ UInt32 mEventType;
+ MusicDeviceGroupID mGroupID;
+ NoteInstanceID mNoteID;
+ UInt32 mOffsetSampleFrame;
+ MusicDeviceNoteParams* mNoteParams;
+ MusicDeviceNoteParams mSmallNoteParams; // inline a small one to eliminate malloc for the simple case.
+};
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#endif
diff --git a/libs/appleutility/CoreAudio/AudioUnits/AUPublic/AUInstrumentBase/SynthNote.cpp b/libs/appleutility/CoreAudio/AudioUnits/AUPublic/AUInstrumentBase/SynthNote.cpp
new file mode 100644
index 0000000000..96a24d33c2
--- /dev/null
+++ b/libs/appleutility/CoreAudio/AudioUnits/AUPublic/AUInstrumentBase/SynthNote.cpp
@@ -0,0 +1,140 @@
+/*
+ File: SynthNote.cpp
+ Abstract: SynthNote.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 "SynthNote.h"
+#include "SynthElement.h"
+#include "AUInstrumentBase.h"
+
+bool SynthNote::AttackNote(
+ SynthPartElement * inPart,
+ SynthGroupElement * inGroup,
+ NoteInstanceID inNoteID,
+ UInt64 inAbsoluteSampleFrame,
+ UInt32 inOffsetSampleFrame,
+ const MusicDeviceNoteParams &inParams)
+{
+#if DEBUG_PRINT
+ printf("SynthNote::AttackNote %lu %lu abs frame %llu rel frame %lu\n", (UInt32)inGroup->GroupID(), (UInt32)inNoteID, inAbsoluteSampleFrame, inOffsetSampleFrame);
+#endif
+ mPart = inPart;
+ mGroup = inGroup;
+ mNoteID = inNoteID;
+
+ mAbsoluteStartFrame = inAbsoluteSampleFrame;
+ mRelativeStartFrame = inOffsetSampleFrame;
+ mRelativeReleaseFrame = -1;
+ mRelativeKillFrame = -1;
+
+ mPitch = inParams.mPitch;
+ mVelocity = inParams.mVelocity;
+
+
+ return Attack(inParams);
+}
+
+
+void SynthNote::Reset()
+{
+ mPart = 0;
+ mGroup = 0;
+ mAbsoluteStartFrame = 0;
+ mRelativeStartFrame = 0;
+ mRelativeReleaseFrame = 0;
+ mRelativeKillFrame = 0;
+}
+
+void SynthNote::Kill(UInt32 inFrame)
+{
+ mRelativeKillFrame = inFrame;
+}
+
+void SynthNote::Release(UInt32 inFrame)
+{
+ mRelativeReleaseFrame = inFrame;
+}
+
+void SynthNote::FastRelease(UInt32 inFrame)
+{
+ mRelativeReleaseFrame = inFrame;
+}
+
+double SynthNote::TuningA() const
+{
+ return 440.0;
+}
+
+double SynthNote::Frequency()
+{
+ return TuningA() * pow(2., (mPitch - 69. + GetPitchBend()) / 12.);
+}
+
+double SynthNote::SampleRate()
+{
+ return GetAudioUnit()->GetOutput(0)->GetStreamFormat().mSampleRate;
+}
+
+AUInstrumentBase* SynthNote::GetAudioUnit() const
+{
+ return (AUInstrumentBase*)mGroup->GetAudioUnit();
+}
+
+Float32 SynthNote::GetGlobalParameter(AudioUnitParameterID inParamID) const
+{
+ return mGroup->GetAudioUnit()->Globals()->GetParameter(inParamID);
+}
+
+void SynthNote::NoteEnded(UInt32 inFrame)
+{
+ mGroup->NoteEnded(this, inFrame);
+ mNoteID = 0xFFFFFFFF;
+}
+
+float SynthNote::GetPitchBend() const
+{
+ return mGroup->GetPitchBend();
+}
+
+
diff --git a/libs/appleutility/CoreAudio/AudioUnits/AUPublic/AUInstrumentBase/SynthNote.h b/libs/appleutility/CoreAudio/AudioUnits/AUPublic/AUInstrumentBase/SynthNote.h
new file mode 100644
index 0000000000..cec6377217
--- /dev/null
+++ b/libs/appleutility/CoreAudio/AudioUnits/AUPublic/AUInstrumentBase/SynthNote.h
@@ -0,0 +1,187 @@
+/*
+ File: SynthNote.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 __SynthNote__
+#define __SynthNote__
+
+#include <AudioUnit/AudioUnit.h>
+#include <CoreAudio/CoreAudio.h>
+#include "MusicDeviceBase.h"
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+enum SynthNoteState {
+ kNoteState_Attacked = 0,
+ kNoteState_Sostenutoed = 1,
+ kNoteState_ReleasedButSostenutoed = 2,
+ kNoteState_ReleasedButSustained = 3,
+ kNoteState_Released = 4,
+ kNoteState_FastReleased = 5,
+ kNoteState_Free = 6,
+ kNumberOfActiveNoteStates = 5,
+ kNumberOfSoundingNoteStates = 6,
+ kNumberOfNoteStates = 7,
+ kNoteState_Unset = kNumberOfNoteStates
+};
+
+/*
+ This table describes the state transitions for SynthNotes
+
+ EVENT CURRENT STATE NEW STATE
+ note on free attacked
+ note off attacked (and sustain on) released but sustained
+ note off attacked released
+ note off sostenutoed released but sostenutoed
+ sustain on -- no changes --
+ sustain off released but sustained released
+ sostenuto on attacked sostenutoed
+ sostenuto off sostenutoed attacked
+ sostenuto off released but sostenutoed (and sustain on) released but sustained
+ sostenuto off released but sostenutoed released
+ end of note any state free
+ soft voice stealing any state fast released
+ hard voice stealing any state free
+
+ soft voice stealing happens when there is a note on event and NumActiveNotes > MaxActiveNotes
+ hard voice stealing happens when there is a note on event and NumActiveNotes == NumNotes (no free notes)
+ voice stealing removes the quietest note in the highest numbered state that has sounding notes.
+*/
+
+class SynthGroupElement;
+class SynthPartElement;
+class AUInstrumentBase;
+
+struct SynthNote
+{
+ SynthNote() :
+ mPrev(0), mNext(0), mPart(0), mGroup(0),
+ mNoteID(0xffffffff),
+ mState(kNoteState_Unset),
+ mAbsoluteStartFrame(0),
+ mRelativeStartFrame(0),
+ mRelativeReleaseFrame(-1),
+ mRelativeKillFrame(-1),
+ mPitch(0.0f),
+ mVelocity(0.0f)
+ {
+ }
+
+ virtual ~SynthNote() {}
+
+ virtual void Reset();
+ //! Returns true if active note resulted from this call, otherwise false
+ virtual bool AttackNote(
+ SynthPartElement * inPart,
+ SynthGroupElement * inGroup,
+ NoteInstanceID inNoteID,
+ UInt64 inAbsoluteSampleFrame,
+ UInt32 inOffsetSampleFrame,
+ const MusicDeviceNoteParams &inParams
+ );
+
+ virtual OSStatus Render(UInt64 inAbsoluteSampleFrame, UInt32 inNumFrames, AudioBufferList** inBufferList, UInt32 inOutBusCount) = 0;
+ //! Returns true if active note resulted from this call, otherwise false
+ virtual bool Attack(const MusicDeviceNoteParams &inParams) = 0;
+ virtual void Kill(UInt32 inFrame); // voice is being stolen.
+ virtual void Release(UInt32 inFrame);
+ virtual void FastRelease(UInt32 inFrame);
+ virtual Float32 Amplitude() = 0; // used for finding quietest note for voice stealing.
+
+ virtual void NoteEnded(UInt32 inFrame);
+
+ SynthGroupElement* GetGroup() const { return mGroup; }
+ SynthPartElement* GetPart() const { return mPart; }
+
+ AUInstrumentBase* GetAudioUnit() const;
+
+ Float32 GetGlobalParameter(AudioUnitParameterID inParamID) const;
+
+ NoteInstanceID GetNoteID() const { return mNoteID; }
+ SynthNoteState GetState() const { return mState; }
+ UInt8 GetMidiKey() const { return (UInt8) mPitch; }
+ UInt8 GetMidiVelocity() const { return (UInt8) mVelocity; }
+
+ Boolean IsSounding() const { return mState < kNumberOfSoundingNoteStates; }
+ Boolean IsActive() const { return mState < kNumberOfActiveNoteStates; }
+ UInt64 GetAbsoluteStartFrame() const { return mAbsoluteStartFrame; }
+ SInt32 GetRelativeStartFrame() const { return mRelativeStartFrame; }
+ SInt32 GetRelativeReleaseFrame() const { return mRelativeReleaseFrame; }
+ SInt32 GetRelativeKillFrame() const { return mRelativeKillFrame; }
+
+ void ListRemove() { mPrev = mNext = 0; } // only use when lists will be reset.
+
+ float GetPitchBend() const;
+ double TuningA() const;
+
+ Float32 GetPitch() const { return mPitch; } // returns raw pitch from MusicDeviceNoteParams
+ virtual double Frequency(); // returns the frequency of note + pitch bend.
+ virtual double SampleRate();
+
+ // linked list pointers
+ SynthNote *mPrev;
+ SynthNote *mNext;
+
+ friend class SynthGroupElement;
+ friend struct SynthNoteList;
+protected:
+ void SetState(SynthNoteState inState) { mState = inState; }
+private:
+ SynthPartElement* mPart;
+ SynthGroupElement* mGroup;
+
+ NoteInstanceID mNoteID;
+ SynthNoteState mState;
+ UInt64 mAbsoluteStartFrame;
+ SInt32 mRelativeStartFrame;
+ SInt32 mRelativeReleaseFrame;
+ SInt32 mRelativeKillFrame;
+
+ Float32 mPitch;
+ Float32 mVelocity;
+};
+
+#endif
+
diff --git a/libs/appleutility/CoreAudio/AudioUnits/AUPublic/AUInstrumentBase/SynthNoteList.cpp b/libs/appleutility/CoreAudio/AudioUnits/AUPublic/AUInstrumentBase/SynthNoteList.cpp
new file mode 100644
index 0000000000..849abd266b
--- /dev/null
+++ b/libs/appleutility/CoreAudio/AudioUnits/AUPublic/AUInstrumentBase/SynthNoteList.cpp
@@ -0,0 +1,93 @@
+/*
+ File: SynthNoteList.cpp
+ Abstract: SynthNoteList.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 "SynthNoteList.h"
+#include <stdexcept>
+
+void SynthNoteList::SanityCheck() const
+{
+ if (mState >= kNoteState_Unset) {
+ throw std::runtime_error("SanityCheck: mState is bad");
+ }
+
+ if (mHead == NULL) {
+ if (mTail != NULL)
+ throw std::runtime_error("SanityCheck: mHead is NULL but not mTail");
+ return;
+ }
+ if (mTail == NULL) {
+ throw std::runtime_error("SanityCheck: mTail is NULL but not mHead");
+ }
+
+ if (mHead->mPrev) {
+ throw std::runtime_error("SanityCheck: mHead has a mPrev");
+ }
+ if (mTail->mNext) {
+ throw std::runtime_error("SanityCheck: mTail has a mNext");
+ }
+
+ SynthNote *note = mHead;
+ while (note)
+ {
+ if (note->mState != mState)
+ throw std::runtime_error("SanityCheck: note in wrong state");
+ if (note->mNext) {
+ if (note->mNext->mPrev != note)
+ throw std::runtime_error("SanityCheck: bad link 1");
+ } else {
+ if (mTail != note)
+ throw std::runtime_error("SanityCheck: note->mNext is nil, but mTail != note");
+ }
+ if (note->mPrev) {
+ if (note->mPrev->mNext != note)
+ throw std::runtime_error("SanityCheck: bad link 2");
+ } else {
+ if (mHead != note)
+ throw std::runtime_error("SanityCheck: note->mPrev is nil, but mHead != note");
+ }
+ note = note->mNext;
+ }
+}
diff --git a/libs/appleutility/CoreAudio/AudioUnits/AUPublic/AUInstrumentBase/SynthNoteList.h b/libs/appleutility/CoreAudio/AudioUnits/AUPublic/AUInstrumentBase/SynthNoteList.h
new file mode 100644
index 0000000000..47a3593018
--- /dev/null
+++ b/libs/appleutility/CoreAudio/AudioUnits/AUPublic/AUInstrumentBase/SynthNoteList.h
@@ -0,0 +1,232 @@
+/*
+ File: SynthNoteList.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 __SynthNoteList__
+#define __SynthNoteList__
+
+#include "SynthNote.h"
+
+#if DEBUG
+#ifndef DEBUG_PRINT
+ #define DEBUG_PRINT 0
+#endif
+ #define USE_SANITY_CHECK 0
+#endif
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+struct SynthNoteList
+{
+ SynthNoteList() : mState(kNoteState_Unset), mHead(0), mTail(0) {}
+
+ bool NotEmpty() const { return mHead != NULL; }
+ bool IsEmpty() const { return mHead == NULL; }
+ void Empty() {
+#if USE_SANITY_CHECK
+ SanityCheck();
+#endif
+ mHead = mTail = NULL;
+ }
+
+ UInt32 Length() const {
+#if USE_SANITY_CHECK
+ SanityCheck();
+#endif
+ UInt32 length = 0;
+ for (SynthNote* note = mHead; note; note = note->mNext)
+ length++;
+ return length;
+ };
+
+ void AddNote(SynthNote *inNote)
+ {
+#if DEBUG_PRINT
+ printf("AddNote(inNote=%p) to state: %lu\n", inNote, mState);
+#endif
+#if USE_SANITY_CHECK
+ SanityCheck();
+#endif
+ inNote->SetState(mState);
+ inNote->mNext = mHead;
+ inNote->mPrev = NULL;
+
+ if (mHead) { mHead->mPrev = inNote; mHead = inNote; }
+ else mHead = mTail = inNote;
+#if USE_SANITY_CHECK
+ SanityCheck();
+#endif
+ }
+
+ void RemoveNote(SynthNote *inNote)
+ {
+#if DEBUG_PRINT
+ printf("RemoveNote(inNote=%p) from state: %lu\n", inNote, mState);
+#endif
+#if USE_SANITY_CHECK
+ SanityCheck();
+#endif
+ if (inNote->mPrev) inNote->mPrev->mNext = inNote->mNext;
+ else mHead = inNote->mNext;
+
+ if (inNote->mNext) inNote->mNext->mPrev = inNote->mPrev;
+ else mTail = inNote->mPrev;
+
+ inNote->mPrev = 0;
+ inNote->mNext = 0;
+#if USE_SANITY_CHECK
+ SanityCheck();
+#endif
+ }
+
+ void TransferAllFrom(SynthNoteList *inNoteList, UInt32 inFrame)
+ {
+#if DEBUG_PRINT
+ printf("TransferAllFrom: from state %lu into state %lu\n", inNoteList->mState, mState);
+#endif
+#if USE_SANITY_CHECK
+ SanityCheck();
+ inNoteList->SanityCheck();
+#endif
+ if (!inNoteList->mTail) return;
+
+ if (mState == kNoteState_Released)
+ {
+ for (SynthNote* note = inNoteList->mHead; note; note = note->mNext)
+ {
+#if DEBUG_PRINT
+ printf("TransferAllFrom: releasing note %p\n", note);
+#endif
+ note->Release(inFrame);
+ note->SetState(mState);
+ }
+ }
+ else
+ {
+ for (SynthNote* note = inNoteList->mHead; note; note = note->mNext)
+ {
+ note->SetState(mState);
+ }
+ }
+
+ inNoteList->mTail->mNext = mHead;
+
+ if (mHead) mHead->mPrev = inNoteList->mTail;
+ else mTail = inNoteList->mTail;
+
+ mHead = inNoteList->mHead;
+
+ inNoteList->mHead = NULL;
+ inNoteList->mTail = NULL;
+#if USE_SANITY_CHECK
+ SanityCheck();
+ inNoteList->SanityCheck();
+#endif
+ }
+
+ SynthNote* FindOldestNote()
+ {
+#if DEBUG_PRINT
+ printf("FindOldestNote\n");
+#endif
+#if USE_SANITY_CHECK
+ SanityCheck();
+#endif
+ UInt64 minStartFrame = -1;
+ SynthNote* oldestNote = NULL;
+ for (SynthNote* note = mHead; note; note = note->mNext)
+ {
+ if (note->mAbsoluteStartFrame < minStartFrame)
+ {
+ oldestNote = note;
+ minStartFrame = note->mAbsoluteStartFrame;
+ }
+ }
+ return oldestNote;
+ }
+
+ SynthNote* FindMostQuietNote()
+ {
+#if DEBUG_PRINT
+ printf("FindMostQuietNote\n");
+#endif
+ Float32 minAmplitude = 1e9f;
+ UInt64 minStartFrame = -1;
+ SynthNote* mostQuietNote = NULL;
+ for (SynthNote* note = mHead; note; note = note->mNext)
+ {
+ Float32 amp = note->Amplitude();
+#if DEBUG_PRINT
+ printf(" amp %g minAmplitude %g\n", amp, minAmplitude);
+#endif
+ if (amp < minAmplitude)
+ {
+ mostQuietNote = note;
+ minAmplitude = amp;
+ minStartFrame = note->mAbsoluteStartFrame;
+ }
+ else if (amp == minAmplitude && note->mAbsoluteStartFrame < minStartFrame)
+ {
+ // use earliest start time as a tie breaker
+ mostQuietNote = note;
+ minStartFrame = note->mAbsoluteStartFrame;
+ }
+ }
+#if USE_SANITY_CHECK
+ SanityCheck();
+#endif
+ return mostQuietNote;
+ }
+
+ void SanityCheck() const;
+
+ SynthNoteState mState;
+ SynthNote * mHead;
+ SynthNote * mTail;
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+#endif