public void RemoveFromRegistry(Voice voice)
 {
     VoiceNode node = registry[voice.VoiceParams.channel, voice.VoiceParams.note];
     if (node == null)
         return;
     if (node.Value == voice)
     {
         registry[voice.VoiceParams.channel, voice.VoiceParams.note] = node.Next;
         vnodes.Push(node);
         return;
     }
     else
     {
         VoiceNode node2 = node;
         node = node.Next;
         while (node != null)
         {
             if (node.Value == voice)
             {
                 node2.Next = node.Next;
                 vnodes.Push(node);
                 return;
             }
             node2 = node;
             node = node.Next;
         }
     }
 }
 public void AddToRegistry(Voice voice)
 {
     VoiceNode node = vnodes.Pop();
     node.Value = voice;
     node.Next = registry[voice.VoiceParams.channel, voice.VoiceParams.note];
     registry[voice.VoiceParams.channel, voice.VoiceParams.note] = node;
 }
 //--Public Methods
 public VoiceManager(int voiceCount)
 {
     stealingMethod = VoiceStealEnum.Quietest;
     polyphony = voiceCount;
     //initialize voice containers
     voicePool = new Voice[voiceCount];
     VoiceNode[] nodes = new VoiceNode[voiceCount];
     for (int x = 0; x < voicePool.Length; x++)
     {
         voicePool[x] = new Voice();
         nodes[x] = new VoiceNode();
     }
     vnodes = new Stack<VoiceNode>(nodes);
     //free voice list
     freeVoices = new LinkedList<Voice>(voicePool);
     activeVoices = new LinkedList<Voice>();
     registry = new VoiceNode[Synthesizer.DefaultChannelCount, Synthesizer.DefaultKeyCount];
 }
        /// <summary>
        /// Starts a voice with the given key and velocity.
        /// </summary>
        /// <param name="channel">The midi channel this voice is on.</param>
        /// <param name="note">The key the voice will play in.</param>
        /// <param name="velocity">The volume of the voice.</param>
        public void NoteOn(int channel, int note, int velocity)
        {
            // Get the correct instrument depending if it is a drum or not
            SynthParameters sChan = synthChannels[channel];
            // Debug.LogFormat("Patch {0} {1}", sChan.bankSelect, sChan.program);
            Patch inst = bank.GetPatch(sChan.bankSelect, sChan.program);

            if (inst == null)
            {
                return;
            }
            // A NoteOn can trigger multiple voices via layers
            int layerCount;

            if (inst is MultiPatch)
            {
                layerCount = ((MultiPatch)inst).FindPatches(channel, note, velocity, layerList);
            }
            else
            {
                layerCount   = 1;
                layerList[0] = inst;
            }
            // If a key with the same note value exists, stop it
            if (voiceManager.registry[channel, note] != null)
            {
                VoiceManager.VoiceNode node = voiceManager.registry[channel, note];
                while (node != null)
                {
                    node.Value.Stop();
                    node = node.Next;
                }
                voiceManager.RemoveFromRegistry(channel, note);
            }
            // Check exclusive groups
            for (int x = 0; x < layerCount; x++)
            {
                bool notseen = true;
                for (int i = x - 1; i >= 0; i--)
                {
                    if (layerList[x].ExclusiveGroupTarget == layerList[i].ExclusiveGroupTarget)
                    {
                        notseen = false;
                        break;
                    }
                }
                if (layerList[x].ExclusiveGroupTarget != 0 && notseen)
                {
                    LinkedListNode <Voice> node = voiceManager.activeVoices.First;
                    while (node != null)
                    {
                        if (layerList[x].ExclusiveGroupTarget == node.Value.Patch.ExclusiveGroup)
                        {
                            node.Value.Stop();
                            voiceManager.RemoveFromRegistry(node.Value);
                        }
                        node = node.Next;
                    }
                }
            }
            // Assign a voice to each layer
            for (int x = 0; x < layerCount; x++)
            {
                Voice voice = voiceManager.GetFreeVoice();
                if (voice == null)// out of voices and skipping is enabled
                {
                    break;
                }
                voice.Configure(channel, note, velocity, layerList[x], synthChannels[channel]);
                voiceManager.AddToRegistry(voice);
                voiceManager.activeVoices.AddLast(voice);
                voice.Start();
            }
            // Clear layer list
            for (int x = 0; x < layerCount; x++)
            {
                layerList[x] = null;
            }
        }