private void HandleMidiNotesChanged(object sender, NotifyCollectionChangedEventArgs e) { IMidiNote[] itemsToRemove; IMidiNote[] itemsToAdd; lock (_voiceLock) { if (e.Action == NotifyCollectionChangedAction.Reset) { // itemsToRemove is everything that used to be in the list but is not in the list now itemsToRemove = _lastNoteList.Where(on => !FindMatchingVoices(on).Any()).ToArray(); // itemsToAdd is evertying that is in the list now that wasn't the list before itemsToAdd = _midiSource.ActiveNotes.Where(on => !_lastNoteList.Any(an => an.Number == on.Number)).ToArray(); } else { itemsToRemove = (e.OldItems ?? new IMidiNote[0]).OfType <IMidiNote>().ToArray(); itemsToAdd = (e.NewItems ?? new IMidiNote[0]).OfType <IMidiNote>().ToArray(); } foreach (int i in Enumerable.Range(0, itemsToRemove.Length)) { IMidiNote note = itemsToRemove[i]; IEnumerable <SimpleVoice> toKill = FindMatchingVoices(note); toKill.Execute(KillNote); } foreach (IMidiNote note in itemsToAdd) { SimpleVoice voice = GetLowestPriorityVoice(); // this could only be null if there are zero voices, which is not allowed if (voice == null) { throw new InvalidOperationException("No voices found."); } voice.FromMidiNote = note; if (NumberOfVoices > 1 || !IsLegato) { voice.Intensity = 0; } SetPitch(voice); if (!voice.IsActive || NumberOfVoices > 1 || !IsLegato) { voice.Intensity = note.Velocity; } voice.IsActive = true; } _lastNoteList = _midiSource.ActiveNotes; } }
private void SetPitch(SimpleVoice voice) { if (voice.FromMidiNote != null) { // TODO this search could be optimized IScaleNote scaleNote = _scale.FirstOrDefault(n => n.MidiNoteNumber == voice.FromMidiNote.Number); if (scaleNote != null) { voice.Pitch = scaleNote.Pitch + (Pitch.HalfStep * PitchBendRange * _midiSource.PitchBend); } } }
public Guid?InjectNote(float pitch, float intensity) { SimpleVoice voice = GetLowestPriorityVoice(); voice.IsActive = false; voice.FromMidiNote = null; voice.Pitch = pitch; voice.Intensity = intensity; voice.Id = Guid.NewGuid(); return(voice.Id); }
private void RemoveVoices() { lock (_voiceLock) { while (_voices.Count > _numberOfVoices) { SimpleVoice voice = GetLowestPriorityVoice(); if (voice != null) { voice.IsActive = false; _voices.Remove(voice); } } } }
private void KillNote(SimpleVoice voice) { voice.FromMidiNote.PropertyChanged -= HandleMidiNotePropertyChanged; voice.IsActive = false; }
private SimpleVoice GetLowestPriorityVoice() { SimpleVoice lowestPriority = _voices.OrderBy(v => !v.IsActive).ThenBy(v => v.StartTime).FirstOrDefault(); return(lowestPriority); }