summaryrefslogtreecommitdiff
path: root/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase
diff options
context:
space:
mode:
Diffstat (limited to 'distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase')
-rwxr-xr-xdistrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/AUInstrumentBase.cpp760
-rwxr-xr-xdistrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/AUInstrumentBase.h246
-rwxr-xr-xdistrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/LockFreeFIFO.h167
-rwxr-xr-xdistrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/SynthElement.cpp266
-rwxr-xr-xdistrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/SynthElement.h262
-rwxr-xr-xdistrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/SynthEvent.h140
-rwxr-xr-xdistrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/SynthNote.cpp113
-rwxr-xr-xdistrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/SynthNote.h170
-rwxr-xr-xdistrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/SynthNoteList.cpp87
-rwxr-xr-xdistrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/SynthNoteList.h226
10 files changed, 2437 insertions, 0 deletions
diff --git a/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/AUInstrumentBase.cpp b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/AUInstrumentBase.cpp
new file mode 100755
index 00000000..f8bfe39e
--- /dev/null
+++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/AUInstrumentBase.cpp
@@ -0,0 +1,760 @@
+/* Copyright © 2007 Apple Inc. All Rights Reserved.
+
+ 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.
+*/
+#include "AUInstrumentBase.h"
+
+#if DEBUG
+ #define DEBUG_PRINT 0
+ #define DEBUG_PRINT_RENDER 0
+#endif
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+const UInt32 kEventQueueSize = 1024;
+
+AUInstrumentBase::AUInstrumentBase(
+ ComponentInstance inInstance,
+ UInt32 numInputs,
+ UInt32 numOutputs,
+ UInt32 numGroups,
+ UInt32 numParts)
+ : MusicDeviceBase(inInstance, numInputs, numOutputs, numGroups, numParts),
+ mAbsoluteSampleFrame(0),
+ mEventQueue(kEventQueueSize),
+ mNumNotes(0),
+ mNumActiveNotes(0),
+ mMaxActiveNotes(0),
+ mNotes(0),
+ mNoteSize(0)
+{
+#if DEBUG_PRINT
+ printf("new AUInstrumentBase\n");
+#endif
+ mFreeNotes.mState = kNoteState_Free;
+}
+
+
+AUInstrumentBase::~AUInstrumentBase()
+{
+#if DEBUG_PRINT
+ printf("delete AUInstrumentBase\n");
+#endif
+}
+
+AUElement* AUInstrumentBase::CreateElement( AudioUnitScope scope,
+ AudioUnitElement element)
+{
+#if DEBUG_PRINT
+ printf("AUInstrumentBase::CreateElement %d %d\n", scope, element);
+#endif
+ switch (scope)
+ {
+ case kAudioUnitScope_Group :
+ return new SynthGroupElement(this, element);
+ case kAudioUnitScope_Part :
+ return new SynthPartElement(this, element);
+ default :
+ return AUBase::CreateElement(scope, element);
+ }
+}
+
+
+void AUInstrumentBase::SetNotes(UInt32 inNumNotes, UInt32 inMaxActiveNotes, SynthNote* inNotes, UInt32 inNoteDataSize)
+{
+#if DEBUG_PRINT
+ printf("AUInstrumentBase::SetNotes %d %d %08X %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->mState <= kNoteState_Released)
+ sum++;
+ }
+ return sum;
+}
+
+void AUInstrumentBase::AddFreeNote(SynthNote* inNote)
+{
+ if (inNote->mState != kNoteState_FastReleased)
+ DecNumActiveNotes();
+#if DEBUG_PRINT
+ printf("AUInstrumentBase::AddFreeNote mNumActiveNotes %lu\n", 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()
+{
+}
+
+
+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);
+
+ UInt32 numOutputs = Outputs().GetNumberOfElements();
+ for (UInt32 j = 0; j < numOutputs; ++j)
+ {
+ 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(inNumberFrames);
+ 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;
+}
+
+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 %d %d\n", inGroupID, inNoteInstanceID);
+#endif
+
+ SynthGroupElement *gp = (inGroupID == kMusicNoteEvent_Unused
+ ? GetElForNoteID (inNoteInstanceID)
+ : GetElForGroupID(inGroupID));
+
+ gp->NoteOff (inNoteInstanceID, inOffsetSampleFrame);
+
+ return noErr;
+}
+
+SynthGroupElement * AUInstrumentBase::GetElForNoteID (NoteInstanceID inNoteID)
+{
+#if DEBUG_PRINT
+ printf("GetElForNoteID id %d\n", (int)inNoteID);
+#endif
+ if (!mNotes) throw std::runtime_error("no notes");
+
+ for (unsigned int i = 0; i < mNumNotes; ++i) {
+ if (inNoteID == mNotes[i].GetNoteID()) {
+ return mNotes[i].GetGroup();
+ }
+ }
+ throw static_cast<OSStatus>(kAudioUnitErr_InvalidElement);
+}
+
+OSStatus AUInstrumentBase::StartNote( MusicDeviceInstrumentID inInstrument,
+ MusicDeviceGroupID inGroupID,
+ NoteInstanceID * outNoteInstanceID,
+ UInt32 inOffsetSampleFrame,
+ const MusicDeviceNoteParams &inParams)
+{
+#if DEBUG_PRINT
+ printf("AUInstrumentBase::StartNote %d\n", inGroupID);
+#endif
+ OSStatus err = noErr;
+
+ NoteInstanceID noteID;
+ if (outNoteInstanceID) {
+ noteID = NextNoteID();
+ *outNoteInstanceID = noteID;
+ } else
+ noteID = (UInt32)inParams.mPitch;
+
+ 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 %d %d\n", inGroupID, inNoteInstanceID);
+#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);
+ 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)
+{
+ GetControls(inChannel)->mControls[inController] = inValue;
+ 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;
+ }
+ return noErr;
+}
+
+OSStatus AUInstrumentBase::HandlePitchWheel( UInt8 inChannel,
+ UInt8 inPitch1,
+ UInt8 inPitch2,
+ UInt32 inStartFrame)
+{
+ MidiControls* controls = GetControls(inChannel);
+ controls->mPitchBend = (inPitch2 << 7) | inPitch1;
+ controls->mFPitchBend = (float)((SInt16)controls->mPitchBend - 8192) / 8192.;
+ return noErr;
+}
+
+
+OSStatus AUInstrumentBase::HandleChannelPressure(UInt8 inChannel,
+ UInt8 inValue,
+ UInt32 inStartFrame)
+{
+ GetControls(inChannel)->mMonoPressure = inValue;
+ return noErr;
+}
+
+
+OSStatus AUInstrumentBase::HandleProgramChange( UInt8 inChannel,
+ UInt8 inValue)
+{
+ GetControls(inChannel)->mMonoPressure = inValue;
+ return noErr;
+}
+
+
+OSStatus AUInstrumentBase::HandlePolyPressure( UInt8 inChannel,
+ UInt8 inKey,
+ UInt8 inValue,
+ UInt32 inStartFrame)
+{
+ GetControls(inChannel)->mPolyPressure[inKey] = inValue;
+ return noErr;
+}
+
+
+OSStatus AUInstrumentBase::HandleResetAllControllers( UInt8 inChannel)
+{
+ SendPedalEvent (inChannel, SynthEvent::kEventType_ResetAllControllers, 0);
+ return noErr;
+}
+
+
+OSStatus AUInstrumentBase::HandleAllNotesOff( UInt8 inChannel)
+{
+ SendPedalEvent (inChannel, SynthEvent::kEventType_AllNotesOff, 0);
+ return noErr;
+}
+
+
+OSStatus AUInstrumentBase::HandleAllSoundOff( UInt8 inChannel)
+{
+ SendPedalEvent (inChannel, SynthEvent::kEventType_AllSoundOff, 0);
+ return noErr;
+}
+
+SynthNote* AUInstrumentBase::GetAFreeNote(UInt32 inFrame)
+{
+#if DEBUG_PRINT
+ printf("GetAFreeNote size %d\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
+ printf("enter voice stealing\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
+ printf(" steal 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
+ printf(" steal group %d size %d\n", j, group->mNoteList[i].Length());
+#endif
+ if (group->mNoteList[i].NotEmpty()) {
+#if DEBUG_PRINT
+ printf("not empty %d %d\n", i, j);
+#endif
+ SynthNote *note = group->mNoteList[i].FindMostQuietNote();
+ if (inKillIt) {
+#if DEBUG_PRINT
+ printf("--=== KILL ===---\n");
+#endif
+ note->mRelativeKillFrame = inFrame;
+ note->Kill(inFrame);
+ group->mNoteList[i].RemoveNote(note);
+ if (i != kNoteState_FastReleased)
+ DecNumActiveNotes();
+ return note;
+ } else {
+#if DEBUG_PRINT
+ printf("--=== 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
+ 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(
+ ComponentInstance 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;
+
+ IncNumActiveNotes();
+ note->AttackNote(NULL, inGroup, inNoteInstanceID,
+ mAbsoluteSampleFrame + inOffsetSampleFrame, inOffsetSampleFrame, inParams);
+
+ inGroup->mNoteList[kNoteState_Attacked].AddNote(note);
+ return noErr;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+OSStatus AUMultitimbralInstrumentBase::GetPropertyInfo(AudioUnitPropertyID inID,
+ AudioUnitScope inScope,
+ AudioUnitElement inElement,
+ UInt32 & outDataSize,
+ Boolean & outWritable)
+{
+ OSStatus result = noErr;
+
+ switch (inID)
+ {
+ case kMusicDeviceProperty_PartGroup:
+ if (inScope != kAudioUnitScope_Part) return kAudioUnitErr_InvalidScope;
+ outDataSize = sizeof(UInt32);
+ outWritable = true;
+ break;
+
+ 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)
+ {
+ case kMusicDeviceProperty_PartGroup:
+ if (inScope != kAudioUnitScope_Group) return kAudioUnitErr_InvalidScope;
+ // ??
+ return -1; //unimpl
+ break;
+
+ 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)
+ {
+ case kMusicDeviceProperty_PartGroup:
+ if (inScope != kAudioUnitScope_Group) return kAudioUnitErr_InvalidScope;
+ // ??
+ return -1; //unimpl
+ break;
+
+ default:
+ result = MusicDeviceBase::SetProperty (inID, inScope, inElement, inData, inDataSize);
+ }
+
+ return result;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
diff --git a/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/AUInstrumentBase.h b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/AUInstrumentBase.h
new file mode 100755
index 00000000..8f779cbf
--- /dev/null
+++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/AUInstrumentBase.h
@@ -0,0 +1,246 @@
+/* Copyright © 2007 Apple Inc. All Rights Reserved.
+
+ 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.
+*/
+#ifndef __AUInstrumentBase__
+#define __AUInstrumentBase__
+
+#include <vector>
+#include <stdexcept>
+#include <AudioUnit/AudioUnit.h>
+#include <CoreAudio/CoreAudio.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(
+ ComponentInstance inInstance,
+ UInt32 numInputs,
+ UInt32 numOutputs,
+ UInt32 numGroups = 32,
+ UInt32 numParts = 0);
+ virtual ~AUInstrumentBase();
+
+ virtual OSStatus Initialize();
+
+ virtual void Cleanup();
+
+ virtual AUElement* CreateElement( AudioUnitScope scope,
+ AudioUnitElement element);
+
+ 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 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);
+
+ MidiControls* GetControls( MusicDeviceGroupID inChannel)
+ {
+ SynthGroupElement *group = GetElForGroupID(inChannel);
+ return &(group->mMidiControls);
+ }
+
+
+protected:
+
+ UInt32 NextNoteID() { return IncrementAtomic(&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();
+ // this call throws if there's no assigned element for the group ID
+ SynthGroupElement * GetElForGroupID (MusicDeviceGroupID inGroupID);
+ SynthGroupElement * GetElForNoteID (NoteInstanceID inNoteID);
+
+ SInt64 mAbsoluteSampleFrame;
+
+
+private:
+
+ SInt32 mNoteIDCounter;
+
+ SynthEventQueue mEventQueue;
+
+ UInt32 mNumNotes;
+ UInt32 mNumActiveNotes;
+ UInt32 mMaxActiveNotes;
+ SynthNote* mNotes;
+ SynthNoteList mFreeNotes;
+ UInt32 mNoteSize;
+};
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+class AUMonotimbralInstrumentBase : public AUInstrumentBase
+{
+public:
+ AUMonotimbralInstrumentBase(
+ ComponentInstance inInstance,
+ UInt32 numInputs,
+ UInt32 numOutputs,
+ UInt32 numGroups = 32,
+ UInt32 numParts = 0);
+
+ 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(
+ ComponentInstance 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/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/LockFreeFIFO.h b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/LockFreeFIFO.h
new file mode 100755
index 00000000..50f97771
--- /dev/null
+++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/LockFreeFIFO.h
@@ -0,0 +1,167 @@
+/* Copyright © 2007 Apple Inc. All Rights Reserved.
+
+ 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.
+*/
+#include <Carbon/Carbon.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.
+ UInt32 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];
+ }
+
+ // 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() { CompareAndSwap(mWriteIndex, (mWriteIndex + 1) & mMask, (UInt32*)&mWriteIndex); }
+ void AdvanceReadPtr() { CompareAndSwap(mReadIndex, (mReadIndex + 1) & mMask, (UInt32*)&mReadIndex); }
+
+private:
+ ITEM* FreeItem()
+ {
+ if (mFreeIndex == mReadIndex) return NULL;
+ return &mItems[mFreeIndex];
+ }
+ void AdvanceFreePtr() { CompareAndSwap(mFreeIndex, (mFreeIndex + 1) & mMask, (UInt32*)&mFreeIndex); }
+
+ void FreeItems()
+ {
+ ITEM* item;
+ while ((item = FreeItem()) != NULL)
+ {
+ item->Free();
+ AdvanceFreePtr();
+ }
+ }
+
+ volatile UInt32 mReadIndex, mWriteIndex, mFreeIndex;
+ UInt32 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()
+ {
+ UInt32 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() { CompareAndSwap(mWriteIndex, (mWriteIndex + 1) & mMask, (UInt32*)&mWriteIndex); }
+ void AdvanceReadPtr() { CompareAndSwap(mReadIndex, (mReadIndex + 1) & mMask, (UInt32*)&mReadIndex); }
+
+private:
+
+ volatile UInt32 mReadIndex, mWriteIndex;
+ UInt32 mMask;
+ ITEM *mItems;
+};
+
diff --git a/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/SynthElement.cpp b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/SynthElement.cpp
new file mode 100755
index 00000000..d16f8e87
--- /dev/null
+++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/SynthElement.cpp
@@ -0,0 +1,266 @@
+/* Copyright © 2007 Apple Inc. All Rights Reserved.
+
+ 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.
+*/
+#include "SynthElement.h"
+#include "AUInstrumentBase.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////
+MidiControls::MidiControls()
+{
+ Reset();
+}
+
+void MidiControls::Reset()
+{
+ memset(this, 0, sizeof(MidiControls));
+ mControls[kMidiController_Pan] = 64;
+ mControls[kMidiController_Expression] = 127;
+ mPitchBendDepth = 2 << 7;
+ mFPitchBendDepth = 2.;
+}
+
+
+SynthElement::SynthElement(AUInstrumentBase *audioUnit, UInt32 inElement)
+ : AUElement(audioUnit), mName(0), mIndex(inElement)
+{
+}
+
+SynthElement::~SynthElement()
+{
+ if (mName) CFRelease(mName);
+}
+
+SynthGroupElement::SynthGroupElement(AUInstrumentBase *audioUnit, UInt32 inElement)
+ : SynthElement(audioUnit, inElement), mSustainIsOn(false), mSostenutoIsOn(false), mOutputBus(0), mGroupID(kUnassignedGroup)
+{
+#if DEBUG_PRINT
+ printf("SynthGroupElement::SynthGroupElement %d\n", inElement);
+#endif
+ for (UInt32 i=0; i<kNumberOfSoundingNoteStates; ++i)
+ mNoteList[i].mState = i;
+}
+
+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
+ mMidiControls.Reset();
+ for (UInt32 i=0; i<kNumberOfSoundingNoteStates; ++i)
+ mNoteList[i].Empty();
+}
+
+SynthPartElement::SynthPartElement(AUInstrumentBase *audioUnit, UInt32 inElement)
+ : SynthElement(audioUnit, inElement)
+{
+}
+
+void SynthGroupElement::NoteOff(NoteInstanceID inNoteID, UInt32 inFrame)
+{
+#if DEBUG_PRINT
+ printf("SynthGroupElement::NoteOff %d\n", inNoteID);
+#endif
+ SynthNote *note = mNoteList[kNoteState_Attacked].mHead;
+ // see if this note is attacked.
+ while (note && note->mNoteID != inNoteID)
+ {
+#if DEBUG_PRINT
+ printf(" ? %08X %d\n", note, note->mNoteID);
+#endif
+ note = note->mNext;
+ }
+
+#if DEBUG_PRINT
+ printf(" found %08X\n", note);
+#endif
+ if (note)
+ {
+#if DEBUG_PRINT
+ printf(" old state %d\n", note->mState);
+#endif
+ mNoteList[kNoteState_Attacked].RemoveNote(note);
+ note->Release(inFrame);
+ if (mSustainIsOn) {
+ mNoteList[kNoteState_ReleasedButSustained].AddNote(note);
+ } else {
+ mNoteList[kNoteState_Released].AddNote(note);
+ }
+#if DEBUG_PRINT
+ printf(" new state %d\n", note->mState);
+#endif
+ }
+ else if (mSostenutoIsOn)
+ {
+ // see if this note is sostenutoed.
+ note = mNoteList[kNoteState_Sostenutoed].mHead;
+ while (note && note->mNoteID != inNoteID)
+ note = note->mNext;
+ if (note)
+ {
+ mNoteList[kNoteState_Sostenutoed].RemoveNote(note);
+ mNoteList[kNoteState_ReleasedButSostenutoed].AddNote(note);
+ }
+ }
+}
+
+void SynthGroupElement::NoteEnded(SynthNote *inNote, UInt32 inFrame)
+{
+#if DEBUG_PRINT
+ printf("SynthGroupElement::NoteEnded %d %d\n", inNote->mNoteID, inNote->mState);
+#endif
+ SynthNoteList *list = mNoteList + inNote->mState;
+ list->RemoveNote(inNote);
+
+ GetAUInstrument()->AddFreeNote(inNote);
+}
+
+void SynthGroupElement::SostenutoOn(UInt32 inFrame)
+{
+#if DEBUG_PRINT
+ printf("SynthGroupElement::SostenutoOn\n");
+#endif
+ mSostenutoIsOn = true;
+ mNoteList[kNoteState_Sostenutoed].TransferAllFrom(&mNoteList[kNoteState_Attacked], inFrame);
+}
+
+void SynthGroupElement::SostenutoOff(UInt32 inFrame)
+{
+#if DEBUG_PRINT
+ printf("SynthGroupElement::SostenutoOff\n");
+#endif
+ 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
+ mSustainIsOn = true;
+}
+
+void SynthGroupElement::SustainOff(UInt32 inFrame)
+{
+#if DEBUG_PRINT
+ printf("SynthGroupElement::SustainOff\n");
+#endif
+ 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<kNumberOfActiveNoteStates; ++i)
+ {
+ note = mNoteList[i].mHead;
+ while (note)
+ {
+ SynthNote *nextNote = note->mNext;
+
+ mNoteList[i].RemoveNote(note);
+ note->FastRelease(inFrame);
+ mNoteList[kNoteState_FastReleased].AddNote(note);
+
+ note = nextNote;
+ }
+ }
+}
+
+void SynthGroupElement::AllSoundOff(UInt32 inFrame)
+{
+#if DEBUG_PRINT
+ printf("SynthGroupElement::AllSoundOff\n");
+#endif
+ AllNotesOff(inFrame);
+}
+
+void SynthGroupElement::ResetAllControllers(UInt32 inFrame)
+{
+#if DEBUG_PRINT
+ printf("SynthGroupElement::ResetAllControllers\n");
+#endif
+ mMidiControls.Reset();
+}
+
+OSStatus SynthGroupElement::Render(UInt32 inNumberFrames)
+{
+ SynthNote *note;
+ AudioBufferList& bufferList = GetAudioUnit()->GetOutput(mOutputBus)->GetBufferList();
+
+ for (UInt32 i=0 ; i<kNumberOfSoundingNoteStates; ++i)
+ {
+ note = mNoteList[i].mHead;
+ while (note)
+ {
+#if DEBUG_PRINT
+ printf(" note %d %08X %d\n", i, note, inNumberFrames);
+#endif
+ SynthNote *nextNote = note->mNext;
+
+ OSStatus err = note->Render(inNumberFrames, bufferList);
+ if (err) return err;
+
+ note = nextNote;
+ }
+ }
+
+ return noErr;
+}
+
+
diff --git a/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/SynthElement.h b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/SynthElement.h
new file mode 100755
index 00000000..a1170730
--- /dev/null
+++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/SynthElement.h
@@ -0,0 +1,262 @@
+/* Copyright © 2007 Apple Inc. All Rights Reserved.
+
+ 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.
+*/
+#ifndef __SynthElement__
+#define __SynthElement__
+
+#include <Carbon/Carbon.h>
+#include <AudioUnit/AudioUnit.h>
+#include "MusicDeviceBase.h"
+#include "SynthNoteList.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(); }
+
+ CFStringRef GetName() const { return mName; }
+ void SetName(CFStringRef inName)
+ {
+ CFStringRef oldName = mName;
+ mName = inName;
+ CFRetain(mName);
+ if (oldName) CFRelease(oldName);
+ }
+private:
+ CFStringRef mName;
+ UInt32 mIndex;
+};
+
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////
+enum {
+ kMidiController_BankSelect = 0,
+ kMidiController_ModWheel = 1,
+ kMidiController_Breath = 2,
+ kMidiController_Foot = 4,
+ kMidiController_PortamentoTime = 5,
+ kMidiController_DataEntry = 6,
+ kMidiController_Volume = 7,
+ kMidiController_Balance = 8,
+ kMidiController_Pan = 10,
+ kMidiController_Expression = 11,
+
+ // these controls have a (0-63) == off, (64-127) == on
+ kMidiController_Sustain = 64, //hold1
+ kMidiController_Portamento = 65,
+ kMidiController_Sostenuto = 66,
+ kMidiController_Soft = 67,
+ kMidiController_LegatoPedal = 68,
+ kMidiController_Hold2Pedal = 69,
+ kMidiController_FilterResonance = 71,
+ kMidiController_ReleaseTime = 72,
+ kMidiController_AttackTime = 73,
+ kMidiController_Brightness = 74,
+ kMidiController_DecayTime = 75,
+ kMidiController_VibratoRate = 76,
+ kMidiController_VibratoDepth = 77,
+ kMidiController_VibratoDelay = 78,
+
+ // these controls have a 0-127 range and in MIDI they have no LSB (so fractional values are lost in MIDI)
+ kMidiController_ReverbLevel = 91,
+ kMidiController_ChorusLevel = 93,
+
+ kMidiController_AllSoundOff = 120,
+ kMidiController_ResetAllControllers = 121,
+ kMidiController_AllNotesOff = 123
+};
+
+struct MidiControls
+{
+ MidiControls();
+ void Reset();
+
+ 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;
+
+ SInt16 GetHiResControl(UInt32 inIndex) const
+ {
+ return ((mControls[inIndex] & 127) << 7) | (mControls[inIndex + 32] & 127);
+ }
+
+ void SetHiResControl(UInt32 inIndex, UInt8 inMSB, UInt8 inLSB)
+ {
+ mControls[inIndex] = inMSB;
+ mControls[inIndex + 32] = inLSB;
+ }
+
+ float GetControl(UInt32 inIndex) const
+ {
+ if (inIndex < 32) {
+ return (float)mControls[inIndex] + (float)mControls[inIndex + 32] / 127.;
+ } else {
+ return (float)mControls[inIndex];
+ }
+ }
+
+ float PitchBend() const { return mFPitchBend * mFPitchBendDepth; }
+
+};
+
+
+class SynthGroupElement : public SynthElement
+{
+public:
+ enum {
+ kUnassignedGroup = 0xFFFFFFFF
+ };
+
+ SynthGroupElement(AUInstrumentBase *audioUnit, UInt32 inElement);
+
+ void NoteOff(NoteInstanceID inNoteID, UInt32 inFrame);
+ void SustainOn(UInt32 inFrame);
+ void SustainOff(UInt32 inFrame);
+ void SostenutoOn(UInt32 inFrame);
+ void SostenutoOff(UInt32 inFrame);
+
+ void NoteEnded(SynthNote *inNote, UInt32 inFrame);
+
+ void AllNotesOff(UInt32 inFrame);
+ void AllSoundOff(UInt32 inFrame);
+ void ResetAllControllers(UInt32 inFrame);
+
+ UInt32 GetOutputBus() const { return mOutputBus; }
+ void SetOutputBus(UInt32 inBus) { mOutputBus = inBus; }
+
+ void Reset();
+
+ virtual OSStatus Render(UInt32 inNumberFrames);
+
+ float GetControl(UInt32 inIndex) const { return mMidiControls.GetControl(inIndex); }
+ float PitchBend() const { return mMidiControls.PitchBend(); }
+
+ MusicDeviceGroupID GroupID () const { return mGroupID; }
+ void SetGroupID (MusicDeviceGroupID inGroup);
+
+private:
+ friend class AUInstrumentBase;
+ friend class AUMonotimbralInstrumentBase;
+ friend class AUMultitimbralInstrumentBase;
+
+ MidiControls mMidiControls;
+
+ bool mSustainIsOn;
+ bool mSostenutoIsOn;
+ UInt32 mOutputBus;
+ MusicDeviceGroupID mGroupID;
+
+
+ SynthNoteList mNoteList[kNumberOfSoundingNoteStates];
+};
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////
+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;
+};
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////
+inline AUInstrumentBase* SynthNote::GetAudioUnit() const
+ {
+ return (AUInstrumentBase*)mGroup->GetAudioUnit();
+ }
+
+inline Float32 SynthNote::GetGlobalParameter(AudioUnitParameterID inParamID) const
+ {
+ return mGroup->GetAudioUnit()->Globals()->GetParameter(inParamID);
+ }
+
+inline void SynthNote::NoteEnded(UInt32 inFrame)
+ {
+ mGroup->NoteEnded(this, inFrame);
+ mNoteID = 0xFFFFFFFF;
+ }
+
+inline float SynthNote::PitchBend() const
+ {
+ return mGroup->PitchBend();
+ }
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#endif
diff --git a/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/SynthEvent.h b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/SynthEvent.h
new file mode 100755
index 00000000..86a439ad
--- /dev/null
+++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/SynthEvent.h
@@ -0,0 +1,140 @@
+/* Copyright © 2007 Apple Inc. All Rights Reserved.
+
+ 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.
+*/
+/* You can either fill in code here or remove this and create or add new files. */
+
+#ifndef __SynthEvent__
+#define __SynthEvent__
+
+#include <Carbon/Carbon.h>
+#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/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/SynthNote.cpp b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/SynthNote.cpp
new file mode 100755
index 00000000..a3c838ca
--- /dev/null
+++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/SynthNote.cpp
@@ -0,0 +1,113 @@
+/* Copyright © 2007 Apple Inc. All Rights Reserved.
+
+ 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.
+*/
+#include "SynthNote.h"
+#include "SynthElement.h"
+#include "AUInstrumentBase.h"
+
+void SynthNote::AttackNote(
+ SynthPartElement * inPart,
+ SynthGroupElement * inGroup,
+ NoteInstanceID inNoteID,
+ SInt64 inAbsoluteSampleFrame,
+ UInt32 inOffsetSampleFrame,
+ const MusicDeviceNoteParams &inParams)
+{
+#if DEBUG_PRINT
+ printf("SynthNote::AttackNote %d %d %d\n", inPart, inGroup->GroupID(), inNoteID);
+#endif
+ mPart = inPart;
+ mGroup = inGroup;
+ mNoteID = inNoteID;
+
+ mAbsoluteStartFrame = inAbsoluteSampleFrame;
+ mRelativeStartFrame = inOffsetSampleFrame;
+ mRelativeReleaseFrame = -1;
+ mRelativeKillFrame = -1;
+
+ mPitch = inParams.mPitch;
+ mVelocity = inParams.mVelocity;
+
+
+ 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. + PitchBend()) / 12.);
+}
+
+double SynthNote::SampleRate()
+{
+ return GetAudioUnit()->GetOutput(0)->GetStreamFormat().mSampleRate;
+}
+
+
diff --git a/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/SynthNote.h b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/SynthNote.h
new file mode 100755
index 00000000..afb1730d
--- /dev/null
+++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/SynthNote.h
@@ -0,0 +1,170 @@
+/* Copyright © 2007 Apple Inc. All Rights Reserved.
+
+ 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.
+*/
+#ifndef __SynthNote__
+#define __SynthNote__
+
+#include <Carbon/Carbon.h>
+#include <AudioUnit/AudioUnit.h>
+#include <CoreAudio/CoreAudio.h>
+#include "MusicDeviceBase.h"
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+enum {
+ 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
+};
+
+/*
+ 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), mState(kNoteState_Free),
+ mRelativeStartFrame(0),
+ mRelativeReleaseFrame(-1),
+ mRelativeKillFrame(-1)
+ {
+ }
+
+ virtual ~SynthNote() {}
+
+ virtual void Reset();
+ virtual void AttackNote(
+ SynthPartElement * inPart,
+ SynthGroupElement * inGroup,
+ NoteInstanceID inNoteID,
+ SInt64 inAbsoluteSampleFrame,
+ UInt32 inOffsetSampleFrame,
+ const MusicDeviceNoteParams &inParams
+ );
+
+ virtual OSStatus Render(UInt32 inNumFrames, AudioBufferList& inBufferList)=0;
+ virtual void 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; }
+ UInt32 GetState() const { return mState; }
+ Boolean IsSounding() const { return mState < kNumberOfSoundingNoteStates; }
+ Boolean IsActive() const { return mState < kNumberOfActiveNoteStates; }
+ SInt64 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 PitchBend() const;
+ double TuningA() const;
+
+ virtual double Frequency(); // returns the frequency of note + pitch bend.
+ double SampleRate();
+
+//private:
+// friend class NoteList;
+
+ // linked list pointers
+ SynthNote *mPrev;
+ SynthNote *mNext;
+
+ SynthPartElement* mPart;
+ SynthGroupElement* mGroup;
+
+ NoteInstanceID mNoteID;
+ UInt32 mState;
+ SInt64 mAbsoluteStartFrame;
+ SInt32 mRelativeStartFrame;
+ SInt32 mRelativeReleaseFrame;
+ SInt32 mRelativeKillFrame;
+
+ Float32 mPitch;
+ Float32 mVelocity;
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+#endif
+
diff --git a/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/SynthNoteList.cpp b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/SynthNoteList.cpp
new file mode 100755
index 00000000..a5ee505b
--- /dev/null
+++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/SynthNoteList.cpp
@@ -0,0 +1,87 @@
+/* Copyright © 2007 Apple Inc. All Rights Reserved.
+
+ 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.
+*/
+#include "SynthNoteList.h"
+#include <stdexcept>
+
+void SynthNoteList::SanityCheck() const
+{
+ if (mState >= kNumberOfNoteStates) {
+ throw std::runtime_error("mState is bad");
+ }
+
+ if (mHead == NULL) {
+ if (mTail != NULL)
+ throw std::runtime_error("mHead is NULL but not mTail");
+ return;
+ }
+ if (mTail == NULL) {
+ throw std::runtime_error("mTail is NULL but not mHead");
+ }
+
+ if (mHead->mPrev) {
+ throw std::runtime_error("mHead has a mPrev");
+ }
+ if (mTail->mNext) {
+ throw std::runtime_error("mTail has a mNext");
+ }
+
+ SynthNote *note = mHead;
+ while (note)
+ {
+ if (note->mState != mState)
+ throw std::runtime_error("note in wrong state");
+ if (note->mNext) {
+ if (note->mNext->mPrev != note)
+ throw std::runtime_error("bad link 1");
+ } else {
+ if (mTail != note)
+ throw std::runtime_error("note->mNext is nil, but mTail != note");
+ }
+ if (note->mPrev) {
+ if (note->mPrev->mNext != note)
+ throw std::runtime_error("bad link 2");
+ } else {
+ if (mHead != note)
+ throw std::runtime_error("note->mPrev is nil, but mHead != note");
+ }
+ note = note->mNext;
+ }
+}
diff --git a/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/SynthNoteList.h b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/SynthNoteList.h
new file mode 100755
index 00000000..5ab7ffa0
--- /dev/null
+++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/SynthNoteList.h
@@ -0,0 +1,226 @@
+/* Copyright © 2007 Apple Inc. All Rights Reserved.
+
+ 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.
+*/
+#ifndef __SynthNoteList__
+#define __SynthNoteList__
+
+#include "SynthNote.h"
+
+#if DEBUG
+#ifndef DEBUG_PRINT
+ #define DEBUG_PRINT 0
+#endif
+ #define SANITY_CHECK 0
+#endif
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+struct SynthNoteList
+{
+ SynthNoteList() : mState(0xFFFFFFFF), mHead(0), mTail(0) {}
+
+ bool NotEmpty() const { return mHead != NULL; }
+ bool IsEmpty() const { return mHead == NULL; }
+ void Empty() {
+#if SANITY_CHECK
+ SanityCheck();
+#endif
+ mHead = mTail = NULL;
+ }
+
+ UInt32 Length() const {
+#if 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 %d %08X\n", mState, inNote);
+#endif
+#if SANITY_CHECK
+ SanityCheck();
+#endif
+ inNote->mState = mState;
+ inNote->mNext = mHead;
+ inNote->mPrev = NULL;
+
+ if (mHead) { mHead->mPrev = inNote; mHead = inNote; }
+ else mHead = mTail = inNote;
+#if SANITY_CHECK
+ SanityCheck();
+#endif
+ }
+
+ void RemoveNote(SynthNote *inNote)
+ {
+#if DEBUG_PRINT
+ printf("RemoveNote\n");
+#endif
+#if 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 SANITY_CHECK
+ SanityCheck();
+#endif
+ }
+
+ void TransferAllFrom(SynthNoteList *inNoteList, UInt32 inFrame)
+ {
+#if DEBUG_PRINT
+ printf("TransferAllFrom\n");
+#endif
+#if 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 release %08X\n", note);
+#endif
+ note->mState = mState;
+ note->Release(inFrame);
+ }
+ }
+ else
+ {
+ for (SynthNote* note = inNoteList->mHead; note; note = note->mNext)
+ {
+ note->mState = 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 SANITY_CHECK
+ SanityCheck();
+ inNoteList->SanityCheck();
+#endif
+ }
+
+ SynthNote* FindOldestNote()
+ {
+#if DEBUG_PRINT
+ printf("FindOldestNote\n");
+#endif
+#if SANITY_CHECK
+ SanityCheck();
+#endif
+ SInt64 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 = 1e9;
+ SInt64 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 SANITY_CHECK
+ SanityCheck();
+#endif
+ return mostQuietNote;
+ }
+
+ void SanityCheck() const;
+
+ UInt32 mState;
+ SynthNote *mHead;
+ SynthNote *mTail;
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+#endif