public void NoteOn(int channel, int note, int velocity)
{
// Get the correct instrument depending if it is a drum or not
var sChan = _synthChannels[channel];
Patch inst = SoundBank.GetPatchByNumber(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)
{
var node = _voiceManager.Registry[channel][note];
while (node != null)
{
node.Value.Stop();
node = node.Next;
}
_voiceManager.RemoveFromRegistry(channel, note);
}
// Check exclusive groups
for (var 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)
{
var node = _voiceManager.ActiveVoices.First;
while (node != null)
{
if (_layerList[x].ExclusiveGroupTarget == node.Value.Patch.ExclusiveGroup)
{
node.Value.Stop();
_voiceManager.RemoveVoiceFromRegistry(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;
}