object ICloneable.Clone() { NoteWithAttackPoint n = (NoteWithAttackPoint)base.Clone(); n.AttackPoint = AttackPoint; return(n); }
/// <summary> /// Returns the likely alphabets for this group, with a score from 0 to 100 representing the probability that each alphabet is correct. /// Alphabets are chosen based on looking at longer notes on stronger beats. /// </summary> /// <returns></returns> public List <Tuple <Alphabet, float> > GetAlphabetsWithLikelihoods() { List <Tuple <Alphabet, float> > results = new List <Tuple <Alphabet, float> >(); int[] attackPointLevels = Measures[0].GetAttackPointLevels(); // Score all possible alphabets. float totalScore = 0; foreach (Alphabet a in possibleGroupAlphabets) { // set up scoring for each pitch in the alphabet. Dictionary <int, float> scores = new Dictionary <int, float>(); // (pitch class, score) Scores between 0 and 1. foreach (ScaleDegree sd in a) { scores[Key.GetScaleDegreePitchClass(sd)] = 0; } // Tally the 1) duration and 2) beat strength for each pitch in the group, if it's found in the alphabet. List <NoteWithAttackPoint> notes = AllNotes; foreach (NoteWithAttackPoint n in notes) { int dur = Math.Min(n.duration, 16); // 1-16 int attack = n.AttackPoint; int level = attackPointLevels[attack]; // stength from 0-4 of beat position. if (n.midiInfo == null) { continue; } int pc = n.midiInfo.PitchClass; if (scores.ContainsKey(pc)) { scores[pc] += (dur / 16.0f) * Constants.ALPHABET_SCORING_DURATION_WEIGHT + (level / 4.0f) * Constants.ALPHABET_SCORING_LEVEL_WEIGHT; } } // Bonus for ending group in chord (just add additional salience to final note). if (notes.Count > 0) { NoteWithAttackPoint n = notes[notes.Count - 1]; if (n.midiInfo != null) { int pc = n.midiInfo.PitchClass; if (scores.ContainsKey(pc)) { int dur = Math.Min(n.duration, 16); // 1-16 scores[pc] += (dur / 16.0f) * Constants.ALPHABET_SCORING_FINAL_NOTE_WEIGHT; } } } // Sum the scores over all notes in the alphabet to get alphabet score. float score = 0; foreach (ScaleDegreeWithStability sd in a) { // TODO: add in small score for non-stable notes too. score += sd.Stability * scores[Key.GetScaleDegreePitchClass(sd)]; } // Bonus for starting piece on tonic chord. if (this.MinLocation == 0 && a.RootScaleDegree.IsTonic) { score *= 5; } //score = 100.0f * (score / 7); results.Add(Tuple.Create(a, score)); totalScore += score; } // Normalize results. List <Tuple <Alphabet, float> > resultsNormalized = new List <Tuple <Alphabet, float> >(); foreach (Tuple <Alphabet, float> x in results) { resultsNormalized.Add(Tuple.Create(x.Item1, 100.0f * x.Item2 / totalScore)); } return(resultsNormalized); }