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; } }