Exemplo n.º 1
0
        /// <summary>
        /// Evaluates the ratio of extreme pitch intervals.
        /// <para> This evaluation checks the pitch interval between every two consecutive
        /// notes and check if the interval is considered extreme or not, in regard to the
        /// <paramref name="maxInterval"/> parameter: If the interval is higher than the
        /// max interval parameter, the distance between the notes would be considered as
        /// an extreme distance. </para>
        /// <para> Besides counting the amount of existing extreme intervals,
        /// this evaluation takes into account the extreme level, i.e., how large in
        /// terms of semitones the interval is, so a two octave interval is considered twice
        /// as extreme than a one octave interval. </para>
        /// <para> The overall fitness is a weighted sum of the ratio between the non-extreme
        /// intervals to the total number of consecutive notes intervals, and the invert ratio
        /// of total semitone distance in the entire melody and the max pitch range. </para>
        /// </summary>
        /// <param name="maxInterval"> Max interval that is considered "okay" between two
        /// consecutive notes. Any interval that exceeds this one would be considered extreme.
        /// </param>
        /// <param name="candidate"> The melody candidate to evaluate. </param>
        /// <returns> The fitness outcome score for the requested evaluation. </returns>
        private protected double EvaluateExtremeIntervals(MelodyCandidate candidate, PitchInterval maxInterval = PitchInterval.PerfectFifth)
        {
            // initialize counters & accumuators
            ulong totalNumOfIntervals   = 0;
            ulong numOfExtremeIntervals = 0;
            ulong overallDeviation      = 0;
            int   adjacentDistance      = 0;

            // init max pitch range
            int pitchRange = MaxPitch - MinPitch;

            // initialize metrics
            double extremeIntervalMetric;
            double overallDeviationMetric;

            // convert max interval nullable int to int
            int maxDistance = (int)maxInterval;

            // retrieve and filter all pitches which are not hold/rest notes
            NotePitch[] pitches = candidate.Bars.GetAllPitches().ToArray();

            // accumulate extreme adjacent notes pitch distance
            for (int i = 0; i < pitches.Length - 1; i++)
            {
                // calculate pitch distance between the two adjacent notes
                adjacentDistance = Math.Abs(pitches[i + 1] - pitches[i]);

                // if this pitch is extreme, update counter & deviation accumulator
                if (adjacentDistance > maxDistance)
                {
                    numOfExtremeIntervals++;
                    overallDeviation += (ulong)(adjacentDistance - maxDistance);
                }
            }

            // set total number of intervals
            totalNumOfIntervals = (ulong)pitches.Length - 1;

            // calculate ratio of extreme intervals which exceed the requested max interval
            extremeIntervalMetric = (totalNumOfIntervals - numOfExtremeIntervals) / (float)totalNumOfIntervals;

            // calculate metric of overal deviation from max interval
            overallDeviationMetric = (numOfExtremeIntervals == 0) ? 1
                : numOfExtremeIntervals / overallDeviation;

            // return weighted fitness according to the two different metrics
            return((0.4 * extremeIntervalMetric) + (0.6 * overallDeviationMetric));
        }
Exemplo n.º 2
0
        /// <summary>
        /// Evaluates how "smooth" the movement is from tone to another.
        /// <para> This evaluation is based on the intervals between consecutive notes
        /// and the notes' degrees in context of their underlying chord.
        /// According to the interval type (perfect, consonants, dissonant) and the
        /// note's degree (chord note, diatonic note, etc) a weighted fitness is set. </para>
        /// </summary>
        /// <param name="candidate"> The melody candidate to evaluate. </param>
        /// <returns> The fitness outcome score for the requested evaluation. </returns>
        private protected double EvaluateSmoothMovement(MelodyCandidate candidate, PitchInterval maxInterval = PitchInterval.PerfectFifth)
        {
            // initialize counters
            ulong totalNumOfIntervals      = 0;
            ulong numOfDiatonicSteps       = 0;
            ulong numOfChordSteps          = 0;
            ulong numOfDissonants          = 0;
            ulong numOfPerfectConsonants   = 0;
            ulong numOfImperfectConsonants = 0;
            ulong numOfTritones            = 0;
            ulong numOfBigLeaps            = 0;
            int   adjacentDistance         = 0;

            // initialize metrics
            double diatonicStepsMetric;
            double chordStepsMetric;
            double intervalTypeMetric;

            // additional initializtions
            double        fitness = 0;
            double        factor  = 0.5; // factor for balancing this fitness function
            PitchInterval interval;
            int           maxDistance = (int)maxInterval;

            // retrieve and filter all pitches which are not hold/rest notes
            NotePitch[] pitches = candidate.Bars.GetAllPitches().ToArray();

            // accumulate extreme adjacent notes pitch distance
            for (int i = 0; i < pitches.Length - 1; i++)
            {
                // calculate pitch distance between the two adjacent notes
                adjacentDistance = Math.Abs(pitches[i + 1] - pitches[i]);

                // update relevant counters according to step size
                Enum.TryParse(adjacentDistance.ToString(), out interval);
                switch (interval)
                {
                case PitchInterval.Unison:
                    numOfPerfectConsonants++;
                    break;

                case PitchInterval.MinorSecond:
                case PitchInterval.MajorSecond:
                    numOfDissonants++;
                    numOfDiatonicSteps++;

                    break;

                case PitchInterval.MinorThird:
                case PitchInterval.MajorThird:
                    numOfChordSteps++;
                    numOfImperfectConsonants++;
                    break;

                case PitchInterval.PerfectFourth:
                    numOfPerfectConsonants++;
                    break;

                case PitchInterval.Tritone:
                    numOfTritones++;
                    break;

                case PitchInterval.PerfectFifth:
                    numOfChordSteps++;
                    numOfPerfectConsonants++;
                    break;

                case PitchInterval.MinorSixth:
                case PitchInterval.MajorSixth:
                    numOfImperfectConsonants++;
                    break;

                case PitchInterval.MinorSeventh:
                case PitchInterval.MajorSeventh:
                    numOfDissonants++;
                    break;

                case PitchInterval.Octave:
                    numOfChordSteps++;
                    numOfPerfectConsonants++;
                    break;

                default:
                    numOfBigLeaps++;
                    break;
                }
            }

            // set total number of intervals
            totalNumOfIntervals = (ulong)pitches.Length - 1;

            // calculate diatonic steps ratio metric
            diatonicStepsMetric = numOfDiatonicSteps / totalNumOfIntervals;

            // calculate chord steps ratio metric
            chordStepsMetric = numOfChordSteps / totalNumOfIntervals;

            // calculate chord steps ratio metric with weighted sum according to interval type
            intervalTypeMetric =
                ((numOfPerfectConsonants * 1.0) +
                 (numOfImperfectConsonants * 0.8) +
                 (numOfDissonants * 0.6) +
                 (numOfTritones * 0.3) +
                 (numOfBigLeaps * 0.1)) / totalNumOfIntervals;

            // calculate total weighted fitness according to the different metrics
            fitness = (0.50 * diatonicStepsMetric) +
                      (0.30 * chordStepsMetric) +
                      (0.20 * intervalTypeMetric);

            // return fitness result
            return(fitness + factor);
        }