ComponentResult 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 noErr; }
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, ¬eState); // 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); } } }
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; }
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. }
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::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); } }
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); 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::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::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; } } }
ComponentResult 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 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; }
void SynthNote::Legato::apply(SynthNote ¬e, float *outl, float *outr) { if(silent) // Silencer if(msg != LM_FadeIn) { memset(outl, 0, synth.bufferbytes); memset(outr, 0, synth.bufferbytes); } try { switch (msg) { case LM_CatchUp: // Continue the catch-up... if (decounter == -10) decounter = fade.length; //Yea, could be done without the loop... for (int i = 0; i < synth.buffersize; ++i) { decounter--; if (decounter < 1) { // Catching-up done, we can finally set // the note to the actual parameters. decounter = -10; msg = LM_ToNorm; LegatoParams pars{param.freq, param.vel, param.portamento, param.midinote, false}; note.legatonote(pars); break; } } break; case LM_FadeIn: // Fade-in if (decounter == -10) decounter = fade.length; silent = false; for (int i = 0; i < synth.buffersize; ++i) { decounter--; if (decounter < 1) { decounter = -10; msg = LM_Norm; break; } fade.m += fade.step; outl[i] *= fade.m; outr[i] *= fade.m; } break; case LM_FadeOut: // Fade-out, then set the catch-up if (decounter == -10) decounter = fade.length; for (int i = 0; i < synth.buffersize; ++i) { decounter--; if (decounter < 1) { for (int j = i; j < synth.buffersize; ++j) { outl[j] = 0.0f; outr[j] = 0.0f; } decounter = -10; silent = true; // Fading-out done, now set the catch-up : decounter = fade.length; msg = LM_CatchUp; //This freq should make this now silent note to catch-up/resync //with the heard note for the same length it stayed at the //previous freq during the fadeout. float catchupfreq = param.freq * (param.freq / lastfreq); LegatoParams pars{catchupfreq, param.vel, param.portamento, param.midinote, false}; note.legatonote(pars); break; } fade.m -= fade.step; outl[i] *= fade.m; outr[i] *= fade.m; } break; default: break; } } catch (std::bad_alloc &ba) { std::cerr << "failed to apply legato: " << ba.what() << std::endl; } }