Example #1
0
        /// <summary>
        ///  Returns an alphabet for a scale in the given key.
        /// </summary>
        /// <param name="bass"></param>
        /// <returns></returns>
        public static Alphabet GetScaleAlphabet(Key k, bool harmonicMinor = false, bool melodicMinor = false)
        {
            Alphabet a = new Alphabet();

            for (int i = 1; i < 8; i++)
            {
                Alteration alteration = Alteration.None;
                if (k.Mode == KeyMode.Minor)
                {
                    if (i == 3 || (i == 6 && !melodicMinor) || (i == 7 && !harmonicMinor && !melodicMinor))
                    {
                        alteration = Alteration.Lowered;
                    }
                }
                int stability;
                switch (i)
                {
                case 1:
                    stability = 3;                              //root
                    break;

                case 3:
                    stability = 1;                              //3rd
                    break;

                case 5:
                    stability = 2;                              //dominant
                    break;

                default:
                    stability = 0;
                    break;
                }
                a.Add(new ScaleDegreeWithStability(i, alteration, stability));
            }

            a.Name            = k.ToString();
            a.RootScaleDegree = new ScaleDegree(1, Alteration.None);
            a.RootPitchClass  = k.GetScaleDegreePitchClass(a.RootScaleDegree);
            a.StepCollection  = true;
            return(a);
        }
Example #2
0
        /// <summary>
        ///  Returns an alphabet for a stacked triadic style chord on the given root in the given key.
        /// </summary>
        /// <param name="bass"></param>
        /// <param name="numStackedThirds">Set to 2 for a normal triad, 3 for a 7th, 4 for a ninth, etc.</param>
        /// <returns></returns>
        static public Alphabet GetStackedTriadAlphabetForBass(Note bass, Key k, Alphabet aScale, int numStackedThirds)
        {
            int bassIdx = -1;

            for (int i = 0; i < aScale.Count; i++)
            {
                ScaleDegree sd = aScale[i];
                if ((bass.Midi - k.GetScaleDegreePitch(sd, 0).MidiNumber) % 12 == 0)
                {
                    bassIdx = i;
                }
            }
            if (bassIdx == -1)
            {
                throw new Exception("Can't compute bass scale degree");
            }

            Alphabet a = GetStackedTriadAlphabetForScaleDegree(k, aScale, numStackedThirds, bassIdx + 1);

            return(a);
        }
Example #3
0
        private static void GenerateAlphabetsForScale(Key key, Alphabet scale, List <Alphabet> alphabetList, bool checkPreviousAlphabets)
        {
            alphabetList.Add(scale);

            // Add all the triads and 7th chords in A melodic minor (skipping duplicates from earlier).
            foreach (ScaleDegree sd in scale.scaleDegrees)
            {
                Pitch p = key.GetScaleDegreePitch(sd, 4);
                Note  n = new Note(0, false, false, new MidiInfo(p.MidiNumber, p.Accidental));
                if (checkPreviousAlphabets)
                {
                    AddIfNew(alphabetList, GetTriadAlphabetForRoot(n, key, scale));
                    AddIfNew(alphabetList, GetSeventhAlphabetForRoot(n, key, scale));
                }
                else
                {
                    alphabetList.Add(GetTriadAlphabetForRoot(n, key, scale));
                    alphabetList.Add(GetSeventhAlphabetForRoot(n, key, scale));
                }
            }
        }
Example #4
0
        static Alphabet()
        {
            // Set up static alphabets.
            Key keyCmajor = new Key();
            Key keyAminor = new Key(0, KeyMode.Minor);

            CMajorAlphabets = new List <Alphabet>();
            AMinorAlphabets = new List <Alphabet>();

            // Set up staticC major alphabets.
            Alphabet CMajorScale = GetScaleAlphabet(keyCmajor);

            GenerateAlphabetsForScale(keyCmajor, CMajorScale, CMajorAlphabets, false);

            // Set up static A minor alphabets.
            Alphabet AMinorScale         = GetScaleAlphabet(keyAminor);
            Alphabet AMelodicMinorScale  = GetScaleAlphabet(keyAminor, false, true);
            Alphabet AHarmonicMinorScale = GetScaleAlphabet(keyAminor, true, false);

            GenerateAlphabetsForScale(keyAminor, AMinorScale, AMinorAlphabets, false);
            GenerateAlphabetsForScale(keyAminor, AMelodicMinorScale, AMinorAlphabets, true);
            GenerateAlphabetsForScale(keyAminor, AHarmonicMinorScale, AMinorAlphabets, true);
        }
Example #5
0
        /// <summary>
        /// Returns a major scale, with stable goals marked on the diven degree and its triad members above it.
        /// </summary>
        /// <param name="key"></param>
        /// <param name="degree">From 1 to 7</param>
        /// <returns></returns>
        static public Alphabet GetMajorScaleAlphabetWithTriadOnDegree(Key key, int degree)
        {
            Alphabet aScale  = GetScaleAlphabet(key);
            Alphabet aStable = GetStackedTriadAlphabetForScaleDegree(key, aScale, 2, degree);

            // Adjust stabilty
            foreach (ScaleDegreeWithStability sd in aScale)
            {
                ScaleDegreeWithStability member;
                if (aStable.Contains(sd, out member))
                {
                    sd.Stability = member.Stability;
                }
                else
                {
                    sd.Stability = 0;
                }
            }
            //aScale.Name += ":" + aStable.Name;
            aScale.Name            = aStable.Name;
            aScale.RootScaleDegree = aStable.RootScaleDegree;
            aScale.RootPitchClass  = aStable.RootPitchClass;
            return(aScale);
        }
Example #6
0
        // Returned list contains one value for each note, computed with simple single-level model
        public List <float> GetNoteExpectednessLarson(Key key, Alphabet alphabet)
        {
            List <NoteWithAttackPoint> notes = this.AllNotes;

            List <float> noteExpectednessLarson = new List <float>(notes.Count);

            Note n1 = null;
            Note n2 = null;

            for (int i = 0; i < notes.Count; i++)
            {
                Note  n3 = notes[i];
                int   G = 0, I = 0;
                float M = 0;

                // Require at least 2 notes for Gravity and Magnetism forces, all 3 required for Inertia.
                if (n2 != null)
                {
                    int         n2MIDI = n2.Midi;
                    ScaleDegree sd2    = n2.GetScaleDegree(key);
                    if (sd2 != null)
                    {
                        int diff2 = n2MIDI - n3.Midi;
                        // Gravity.

                        if (diff2 > 0 && (sd2 == null || !sd2.IsTonic))
                        {
                            G = 1;
                        }

                        // Magnetism.
                        // Is previous note a stable note? If so, no prediction.
                        if (!alphabet.isStable(sd2))
                        {
                            // Not stable. Compute the magnetism based on the distance in half-steps to the nearest goals from the 2nd pitch.

                            // Go up until we find a stable note.
                            int stableAboveMidi = -1;
                            int stableBelowMidi = -1;

                            for (int midi = n2MIDI + 1; ; midi++)
                            {
                                ScaleDegree sdx = new Note(-1, false, false, new MidiInfo(midi, Accidental.Natural)).GetScaleDegree(key);
                                if (sdx != null)
                                {
                                    if (alphabet.isStable(sdx))
                                    {
                                        stableAboveMidi = midi;
                                        break;
                                    }
                                }
                            }
                            for (int midi = n2MIDI - 1; ; midi--)
                            {
                                ScaleDegree sdx = new Note(-1, false, false, new MidiInfo(midi, Accidental.Natural)).GetScaleDegree(key);
                                if (sdx != null)
                                {
                                    if (alphabet.isStable(sdx))
                                    {
                                        stableBelowMidi = midi;
                                        break;
                                    }
                                }
                            }

                            int distAbove = stableAboveMidi - n2MIDI;
                            int distBelow = n2MIDI - stableBelowMidi;

                            float mag    = 1.0f / (distAbove * distAbove) - 1.0f / (distBelow * distBelow);
                            float magMag = Math.Abs(mag); // magnitude of magnetism

                            // Test direction
                            if (diff2 * mag > 0)
                            {
                                // Going in opposite direction (because diff2 is positive when going down and mag is positive when going up.
                                M = -magMag;
                            }
                            else
                            {
                                // Going in same direction.
                                M = magMag;
                            }
                        }

                        // Inertia.
                        if (n1 != null)
                        {
                            int diff1 = n1.Midi - n2.Midi;
                            if (diff1 != 0)
                            {
                                I = (diff1 * diff2 > 0) ? 1 : -1;
                            }
                        }
                    }
                }

                /// Compute force of expecting this note.
                float force = G * Constants.LARSON_WEIGHT_G + I * Constants.LARSON_WEIGHT_I + M * Constants.LARSON_WEIGHT_M;
                noteExpectednessLarson.Add(force);
                //throw new Exception("Force computed: " + force.ToString());

                n1 = n2;
                n2 = n3;
            }
            return(noteExpectednessLarson);
        }
Example #7
0
        public override void Run()
        {
            if (e == null)
            {
                // For now, just pick groups, not measures.
                //e = workspace.PickRandomGroupElementByRecency();
                e = workspace.PickRandomGroupElementByRecency();
            }

            if (e == null)
            {
                return;
            }

            if (!workspace.GroupElements.Contains(e))
            {
                return;
            }

            // Only look at 1-4 measure long groups.
            if (e.LengthInMeasures < 1 || e.LengthInMeasures > 4)
            {
                return;
            }

            // Add to attention history.
            workspace.RecordCodeletAttentionHistory(this, e.MinLocation, e.MaxLocation);

            // Generate possible alphabets and scores.
            List <Tuple <Alphabet, float> > alphabets = e.GetAlphabetsWithLikelihoods();

            // TODO: transition probs.
            // Is there an alphabet in the previous group?
            float[]      transitionProbs = new float[alphabets.Count];
            GroupElement ePrev           = workspace.GetPreviousGroupElement(e);
            Alphabet     aPrev           = null;

            if (ePrev != null)
            {
                aPrev = ePrev.Alphabet;
            }

            if (aPrev == null)
            {
                // No previous alphabet.
                for (int i = 0; i < alphabets.Count; i++)
                {
                    transitionProbs[i] = 1.0f;
                }
            }
            else
            {
                // Previous alphabet known.
                for (int i = 0; i < alphabets.Count; i++)
                {
                    float    prob = 1.0f;
                    Alphabet a    = alphabets[i].Item1;

                    // Estimate transition probability. Weights dont' have to sum to 1.
                    int diff = ((aPrev.RootPitchClass + 24) - a.RootPitchClass) % 12;
                    if (diff == 0)
                    {
                        prob = 1.5f;                            // self transition is tricky.
                    }
                    else if (diff == 7)
                    {
                        prob = 3.0f;
                    }
                    else if (aPrev.RootScaleDegree.Number == 4 && a.RootScaleDegree.Number == 5)
                    {
                        prob = 3.0f;
                    }
                    else if (aPrev.RootScaleDegree.Number == 5 && a.RootScaleDegree.Number == 1)
                    {
                        prob = 5.0f;
                    }
                    else if ((aPrev.RootScaleDegree.Number + 7 - a.RootScaleDegree.Number) % 7 == 2)
                    {
                        prob = 2.0f;
                    }

                    transitionProbs[i] = prob;
                }
            }

            // Is there an alphabet already?
            Alphabet existing = e.Alphabet;

            if (existing == null)
            {
                // Multiply by transition probabilities from previous group.
                List <Utilities.ObjectValuePair> pairs = ConvertTupleListToPairsAndMultiplyByWeights(alphabets, transitionProbs);

                // Pick one!
                Utilities.ObjectValuePair pair = Utilities.PickItemWeightedReturnPair(pairs);

                e.Alphabet         = (Alphabet)pair.obj;
                e.AlphabetStrength = pair.value;
                return;
            }

            // An alphabet already exists. Need to compeete. Also, take into account previous measure alphabet and transition probability.
            Utilities.ObjectValuePair choice = Utilities.PickItemWeightedReturnPair(ConvertTupleListToPairsAndMultiplyByWeights(alphabets, transitionProbs));
            if (Utilities.FightItOut(choice.value, e.AlphabetStrength, workspace.Temperature))
            {
                // The new alphabet won. Replace.
                e.Alphabet         = (Alphabet)choice.obj;
                e.AlphabetStrength = choice.value;
            }
        }
Example #8
0
        static public Alphabet GetAlphabetFromScaleWithTriadOnDegree(Key key, Alphabet scale, ScaleDegree sd)
        {
            Alphabet a = (Alphabet)scale.Clone();

            // record the index of the root.
            int rootDegree = -1;

            for (int i = 0; i < a.Count; i++)
            {
                ScaleDegreeWithStability sds = a[i];
                if (sds.Number == sd.Number && sds.Alteration == sd.Alteration)
                {
                    rootDegree = i;
                    break;
                }
            }

            // Assign stability for each alphabet member.
            for (int j = 0; j < a.Count; j++)
            {
                ScaleDegreeWithStability sds = a[(rootDegree + j) % a.Count];                   // start at the root, and go up 7 scale degrees (with mod to wrap around)
                int stability;
                switch (j)
                {
                case 0:
                    stability = 3;                             // root;
                    break;

                case 2:
                    stability = 1;                             // 3rd
                    break;

                case 3:
                    stability = 2;                             // 5th
                    break;

                default:
                    stability = 0;                              // other thirds
                    break;
                }
                sds.Stability = stability;
            }

            a.Name = key.GetScaleDegreePitch(sd, 4).ToString();


            // Get quality of first third.
            int pc1  = key.GetScaleDegreePitchClass(a[rootDegree]);
            int pc2  = key.GetScaleDegreePitchClass(a[(rootDegree + 2) % a.Count]) + 12;
            int diff = (pc2 - pc1) % 12;

            if (diff == 3)
            {
                a.Name += "m";
            }

            //a.Name += " triad";
            a.RootScaleDegree = sd;
            a.RootPitchClass  = key.GetScaleDegreePitchClass(sd);
            return(a);
        }
Example #9
0
        /// <summary>
        ///  Returns an alphabet for a 7th chord on the given root in the given key.
        /// </summary>
        /// <param name="bass"></param>
        /// <returns></returns>
        static public Alphabet GetSeventhAlphabetForRoot(Note bass, Key k, Alphabet aScale)
        {
            Alphabet a = GetStackedTriadAlphabetForBass(bass, k, aScale, 3);

            return(a);
        }
Example #10
0
        public override void Run()
        {
            if (group == null)
            {
                group = workspace.PickRandomGroupByRecency();
            }

            if (group == null)
            {
                return;
            }

            if (!workspace.groups.Contains(group))
            {
                return;
            }

            // Add to attention history.
            workspace.RecordCodeletAttentionHistory(this, group.MinLocation);
            workspace.RecordCodeletAttentionHistory(this, group.MaxLocation);


            // Check the final note of the rhythm.
            // Score based on the duration and tonic/dominantness of the pitch.

            Measure m = group.Measures[group.Measures.Count - 1];
            Note    n = m.rhythm.notes[m.rhythm.notes.Count - 1];

            if (n.midiInfo == null)
            {
                return;
            }

            ScaleDegree degree = n.midiInfo.GetScaleDegree(new Key());                  // assume C major.
            int         dur    = n.duartionIncludingTiesAfter;

            double score = 0;

            // check for minor/chromatic.
            if (degree == null)
            {
                // maybe its minor (TODO: crude)
                degree = n.midiInfo.GetScaleDegree(new Key());                  // assume C minor.
            }

            // maybe it's chromatic
            if (degree == null)
            {
                return;
            }
            else
            {
                switch (degree.Number)
                {
                case 1:                         // tonic
                    score = 100;

                    break;

                case 5:                         // dominant
                    score = 100;
                    break;

                case 2:                         // supertonic
                    score = 30;
                    break;

                default:
                    return;
                }
            }

            // Now average in harmonic context of pitch, if available.
            double   str1     = group.AlphabetStrength;
            double   str2     = m.AlphabetStrength;
            Alphabet alphabet = null;

            if (str1 >= str2)
            {
                alphabet = group.Alphabet;
            }
            else
            {
                alphabet = m.Alphabet;
            }
            if (alphabet != null)
            {
                // Average in 0 or 100 points depending on stability
                if (alphabet.isStable(degree))
                {
                    score = (score + 100) / 2;
                }
                else
                {
                    score = (score + 0) / 2;
                }
            }

            // Duration
            if (dur < 8)
            {
                score = score * (dur / 8.0);
            }

            if (score > 25)
            {
                if (degree.Number == 1)
                {
                    group.AddGroupReason(new GroupReasonEndTonic(group, score));
                }
                else
                {
                    group.AddGroupReason(new GroupReasonEndDominant(group, score));
                }
            }
        }