public static ChordPattern FromString(string pattern) { if (string.IsNullOrEmpty(pattern)) { throw new ArgumentNullException("pattern"); } string[] words = pattern.Split(new char[] { ',' }); var cp = new ChordPattern(); foreach (string word in words.Where(w => !String.IsNullOrWhiteSpace(w))) { string candidate = word.Trim(); Accidental accidental = Accidental.FromString(candidate); if (accidental != null) { candidate = candidate.Substring(1); } int value = Convert.ToInt32(candidate, CultureInfo.CurrentCulture); if (value > 0) { if (accidental != null) { value += accidental.Value; } var degrees = new ScaleDegree[] { ScaleDegree.First, ScaleDegree.Second, ScaleDegree.Third, ScaleDegree.Fourth, ScaleDegree.Fifth, ScaleDegree.Sixth, ScaleDegree.Seventh, ScaleDegree.Octave, ScaleDegree.FlatNinth, ScaleDegree.Ninth, ScaleDegree.SharpNinth, ScaleDegree.Eleventh, ScaleDegree.SharpEleventh, ScaleDegree.Thirteen }; if (value < 1 || value > degrees.Length) { throw new ArgumentOutOfRangeException("pattern", string.Format(CultureInfo.CurrentCulture, "Don't understand chord degree {0} -> {1}", words, value)); } cp.Add(degrees[value - 1]); } } return(cp); }
private Mode(ScaleDegree scaleDegree, Mode baseMode) { ScaleDegree = scaleDegree; BaseMode = baseMode; Scale = baseMode == null ? Scale.Major : new ModeScale(this, baseMode); }
public void GetCorrectScaleDegree(int pitch, ScaleDegree expectedScaleDegree) { var scaleDegreeEvaluator = new ScaleDegreeEvaluator(); var scaleDegree = scaleDegreeEvaluator.GetScaleDegreeFromNote(pitch); Assert.AreEqual(expectedScaleDegree, scaleDegree); }
public void ScaleDegreeConstructor() { ScaleDegree d = new ScaleDegree(4, Alteration.Raised); Assert.AreEqual(4, d.Number); Assert.AreEqual(Alteration.Raised, d.Alteration); }
/// <summary> /// Gets <see cref="NoteName"/> corresponding to the specified degree of a musical scale. /// </summary> /// <param name="scale"><see cref="Scale"/> to get degree of.</param> /// <param name="degree"><see cref="ScaleDegree"/> representing a degree of the /// <paramref name="scale"/>.</param> /// <returns>The degree of the scale.</returns> /// <exception cref="ArgumentNullException"><paramref name="scale"/> is null.</exception> /// <exception cref="InvalidEnumArgumentException"><paramref name="degree"/> specified an /// invalid value.</exception> /// <exception cref="ArgumentOutOfRangeException"><paramref name="degree"/> is out of /// range for the <paramref name="scale"/>.</exception> public static NoteName GetDegree(this Scale scale, ScaleDegree degree) { ThrowIfArgument.IsNull(nameof(scale), scale); ThrowIfArgument.IsInvalidEnumValue(nameof(degree), degree); ThrowIfDegreeIsOutOfRange(scale, degree); return(scale.GetStep((int)degree)); }
public void AccidentalGetSet() { ScaleDegree d = new ScaleDegree(); Assert.AreEqual(Alteration.None, d.Alteration); d.Alteration = Alteration.Augmented; Assert.AreEqual(Alteration.Augmented, d.Alteration); }
/// <summary> /// Is the given ScaleDegree a seventh with this ScaleDegree? /// </summary> /// <param name="left">The left ScaleDegree for comparison</param> /// <param name="right">The right ScaleDegree for comparison</param> /// <returns>Whether the scale degrees are a seventh apart or not</returns> public static bool IsSeventhWith(this ScaleDegree left, ScaleDegree right) { if (left == ScaleDegree.Root && right == ScaleDegree.Seventh) { return(true); } return(left == ScaleDegree.Seventh && right == ScaleDegree.Root); }
/// <summary> /// Is the given ScaleDegree a tritone with this ScaleDegree? /// See <a href="https://en.wikipedia.org/wiki/Tritone">this link</a> for more information. /// </summary> /// <param name="left">The left ScaleDegree for comparison</param> /// <param name="right">The right ScaleDegree for comparison</param> /// <returns>Whether the scale degrees create a tritone or not</returns> public static bool IsTritoneWith(this ScaleDegree left, ScaleDegree right) { if (left == ScaleDegree.Seventh && right == ScaleDegree.Fourth) { return(true); } return(left == ScaleDegree.Fourth && right == ScaleDegree.Seventh); }
public bool Contains(ScaleDegree sd) { foreach (ScaleDegree x in scaleDegrees) { if (x.Number == sd.Number && x.Alteration == sd.Alteration) { return(true); } } return(false); }
private static void ThrowIfDegreeIsOutOfRange(Scale scale, ScaleDegree degree) { var degreeNumber = (int)degree; if (degreeNumber >= scale.Intervals.Count()) { throw new ArgumentOutOfRangeException(nameof(degree), degree, "Degree is out of range for the scale."); } }
public void NumberSetGet() { ScaleDegree d = new ScaleDegree(); Assert.AreEqual(1, d.Number); d.Number = 7; Assert.AreEqual(7, d.Number); d.Number = 1; Assert.AreEqual(1, d.Number); }
public int GetIndexOfScaleDegree(ScaleDegree sd) { for (int i = 0; i < scaleDegrees.Count; i++) { ScaleDegree x = scaleDegrees[i]; if (x.Number == sd.Number && x.Alteration == sd.Alteration) { return(i); } } return(-1); }
public bool Contains(ScaleDegree sd, out ScaleDegreeWithStability found) { foreach (ScaleDegreeWithStability x in scaleDegrees) { if (x.Number == sd.Number && x.Alteration == sd.Alteration) { found = x; return(true); } } found = null; return(false); }
public Note this[ScaleDegree degree] { get { int index = (int)degree; if (index < 0 || index >= this.scale.Count) { throw new ArgumentOutOfRangeException("degree", "This degree does not exist in this scale"); } return(this.scale[index]); } }
// Finds the scale degree in the alphabet. Returns stability. public bool isStable(ScaleDegree sd) { if (sd == null) { return(false); } foreach (ScaleDegreeWithStability sds in scaleDegrees) { if (sds.Alteration == sd.Alteration && sds.Number == sd.Number) { return(sds.IsStable); } } throw new Exception("ScaleDegree '" + sd.ToString() + "' not found in alphabet: " + this.ToString()); }
/// <summary> /// CompositionContext constructor: initialize class properties with explicit values. /// </summary> /// <param name="counterPointNoteMotion">The counterpoint note motion</param> /// <param name="counterPointNoteMotionSpan">The counterpoint note motion span</param> /// <param name="counterPointNoteScaleDegree">The counterpoint note scale degree</param> /// <param name="cantusFirmusNoteMotion">The cantus firmus note motion</param> /// <param name="cantusFirmusNoteMotionSpan">The cantus firmus note motion span</param> /// <param name="cantusFirmusNoteScaleDegree">The cantus firmus scale degree</param> public CompositionContext( NoteMotion counterPointNoteMotion, NoteMotionSpan counterPointNoteMotionSpan, ScaleDegree counterPointNoteScaleDegree, NoteMotion cantusFirmusNoteMotion, NoteMotionSpan cantusFirmusNoteMotionSpan, ScaleDegree cantusFirmusNoteScaleDegree ) { CounterPointNoteMotion = counterPointNoteMotion; CounterPointNoteMotionSpan = counterPointNoteMotionSpan; CounterPointNoteScaleDegree = counterPointNoteScaleDegree; CantusFirmusNoteMotion = cantusFirmusNoteMotion; CantusFirmusNoteMotionSpan = cantusFirmusNoteMotionSpan; CantusFirmusNoteScaleDegree = cantusFirmusNoteScaleDegree; }
/// <summary> /// Return the distance from n1 up to n2 in this alphabet and given key. /// Returns -1 if notes are not both in the alphabet. /// </summary> /// <param name="n1"></param> /// <param name="n2"></param> /// <param name="k"></param> /// <returns></returns> public int AlphabetDistance(Note n1, Note n2, Key k) { ScaleDegree s1 = n1.GetScaleDegree(k); ScaleDegree s2 = n1.GetScaleDegree(k); if (s1 == null || s2 == null) { return(-1); } // What is distance in alphabet? int dist = 0; // Go up until we find note2. int idx1 = this.GetIndexOfScaleDegree(s1); int sdIndex = idx1; int octave = n1.GetOctave(); Pitch p = k.GetScaleDegreePitch(this[sdIndex], octave); Pitch pOld = p; while (p.MidiNumber < n2.Midi) { sdIndex++; if (sdIndex >= this.Count) { sdIndex = 0; } dist++; p = k.GetScaleDegreePitch(this[sdIndex], octave); if (p.MidiNumber < pOld.MidiNumber) { octave++; p.Octave++; } pOld = p; } if (p.MidiNumber != n2.Midi) // overshot { return(-1); } else { return(dist); } }
/// <summary> /// Override for creating a CompositionContext with specified values. /// </summary> /// <param name="counterPointNoteMotion">The counterpoint NoteMotion to use</param> /// <param name="counterPointNoteMotionSpan">The counterpoint NoteMotionSpan to use</param> /// <param name="counterPointNoteScaleDegree">The counterpoint ScaleDegree to use</param> /// <param name="cantusFirmusNoteMotion">The cantus firmus NoteMotion to use</param> /// <param name="cantusFirmusNoteMotionSpan">The cantus firmus NoteMotionSpan to use</param> /// <param name="cantusFirmusNoteScaleDegree">The cantus firmus ScaleDegree to use</param> /// <returns></returns> public CompositionContext CreateCompositionContext( NoteMotion counterPointNoteMotion, NoteMotionSpan counterPointNoteMotionSpan, ScaleDegree counterPointNoteScaleDegree, NoteMotion cantusFirmusNoteMotion, NoteMotionSpan cantusFirmusNoteMotionSpan, ScaleDegree cantusFirmusNoteScaleDegree ) { return(new CompositionContext( counterPointNoteMotion, counterPointNoteMotionSpan, counterPointNoteScaleDegree, cantusFirmusNoteMotion, cantusFirmusNoteMotionSpan, cantusFirmusNoteScaleDegree )); }
/// <summary> /// Gets <see cref="NoteName"/> corresponding to the specified degree of a musical scale. /// </summary> /// <param name="scale"><see cref="Scale"/> to get degree of.</param> /// <param name="degree"><see cref="ScaleDegree"/> representing a degree of the /// <paramref name="scale"/>.</param> /// <returns>The degree of the scale.</returns> /// <exception cref="ArgumentNullException"><paramref name="scale"/> is null.</exception> /// <exception cref="InvalidEnumArgumentException"><paramref name="degree"/> specified an /// invalid value.</exception> /// <exception cref="ArgumentOutOfRangeException"><paramref name="degree"/> is out of /// range for the <paramref name="scale"/>.</exception> public static NoteName GetDegree(this Scale scale, ScaleDegree degree) { ThrowIfArgument.IsNull(nameof(scale), scale); ThrowIfArgument.IsInvalidEnumValue(nameof(degree), degree); var degreeNumber = (int)degree; if (degreeNumber >= scale.Intervals.Count()) { throw new ArgumentOutOfRangeException(nameof(degree), degree, "Degree is out of range for the scale."); } return(scale.GetNotes() .Skip(degreeNumber) .First() .NoteName); }
/// <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); }
/// <summary> /// Is the given ScaleDegree perfect with this ScaleDegree? /// See <a href="https://en.wikipedia.org/wiki/Perfect_fourth">this link</a> for more information. /// See <a href="https://en.wikipedia.org/wiki/Perfect_fifth">this link</a> for more information. /// </summary> /// <param name="left">The left ScaleDegree for comparison</param> /// <param name="right">The right ScaleDegree for comparison</param> /// <returns>Whether the scale degrees are perfect or not</returns> public static bool IsPerfectWith(this ScaleDegree left, ScaleDegree right) { if (left == ScaleDegree.Root && right == ScaleDegree.Fifth) { return(true); } if (left == ScaleDegree.Fifth && right == ScaleDegree.Root) { return(true); } if (left == ScaleDegree.Second && right == ScaleDegree.Sixth) { return(true); } if (left == ScaleDegree.Sixth && right == ScaleDegree.Second) { return(true); } if (left == ScaleDegree.Third && right == ScaleDegree.Seventh) { return(true); } if (left == ScaleDegree.Seventh && right == ScaleDegree.Third) { return(true); } if (left == ScaleDegree.Fourth && right == ScaleDegree.Root) { return(true); } return(left == ScaleDegree.Root && right == ScaleDegree.Fourth); }
/// <summary> /// CompositionContext constructor. /// </summary> /// <param name="previousNotes">The previous notes in the composition</param> /// <param name="currentNotes">The current notes in the composition</param> /// <param name="scaleDegreeEvaluator">ScaleDegreeEvaluator used to help initialize class properties</param> public CompositionContext(NotePair previousNotes, NotePair currentNotes, ScaleDegreeEvaluator scaleDegreeEvaluator) { CantusFirmusNoteScaleDegree = scaleDegreeEvaluator.GetScaleDegreeFromNote(currentNotes.CantusFirmusNote); CantusFirmusNoteMotion = GetNoteMotionFromNotes( previousNotes.CantusFirmusNote, currentNotes.CantusFirmusNote ); CantusFirmusNoteMotionSpan = GetNoteMotionSpanFromNotes( previousNotes.CantusFirmusNote, currentNotes.CantusFirmusNote ); CounterPointNoteScaleDegree = scaleDegreeEvaluator.GetScaleDegreeFromNote(currentNotes.CounterPointNote); CounterPointNoteMotion = GetNoteMotionFromNotes( previousNotes.CounterPointNote, currentNotes.CounterPointNote ); CounterPointNoteMotionSpan = GetNoteMotionSpanFromNotes( previousNotes.CounterPointNote, currentNotes.CounterPointNote ); }
private void Sharpen(ScaleDegree degree) { SetDegreeQuality(degree, NoteQuality.Sharp); }
private void SetDegreeQuality(ScaleDegree degree, NoteQuality quality) { _noteQualities[(int) degree] = quality; }
private void Flatten(ScaleDegree degree) { SetDegreeQuality(degree, NoteQuality.Flat); }
public void GetAlphabetFromScaleWithTriadOnDegreeTest() { Key key = new Key(0, KeyMode.Minor); // C minor Alphabet scale = Alphabet.GetScaleAlphabet(key); ScaleDegree sd = new ScaleDegree(3, Alteration.Lowered); Alphabet a = Alphabet.GetAlphabetFromScaleWithTriadOnDegree(key, scale, sd); Assert.AreEqual(1, a[0].Number); Assert.AreEqual(Alteration.None, a[0].Alteration); Assert.AreEqual(false, a[0].IsStable); Assert.AreEqual(2, a[1].Number); Assert.AreEqual(Alteration.None, a[1].Alteration); Assert.AreEqual(false, a[1].IsStable); Assert.AreEqual(3, a[2].Number); Assert.AreEqual(Alteration.Lowered, a[2].Alteration); Assert.AreEqual(true, a[2].IsStable); Assert.AreEqual(4, a[3].Number); Assert.AreEqual(Alteration.None, a[3].Alteration); Assert.AreEqual(false, a[3].IsStable); Assert.AreEqual(5, a[4].Number); Assert.AreEqual(Alteration.None, a[4].Alteration); Assert.AreEqual(true, a[4].IsStable); Assert.AreEqual(6, a[5].Number); Assert.AreEqual(Alteration.Lowered, a[5].Alteration); Assert.AreEqual(false, a[5].IsStable); Assert.AreEqual(7, a[6].Number); Assert.AreEqual(Alteration.Lowered, a[6].Alteration); Assert.AreEqual(true, a[6].IsStable); key = new Key(-1, KeyMode.Minor); // F minor scale = Alphabet.GetScaleAlphabet(key); sd = new ScaleDegree(2, Alteration.None); a = Alphabet.GetAlphabetFromScaleWithTriadOnDegree(key, scale, sd); Assert.AreEqual("F", key.GetScaleDegreePitch(a[0], 4).ToString()); Assert.AreEqual(1, a[0].Number); Assert.AreEqual(Alteration.None, a[0].Alteration); Assert.AreEqual(false, a[0].IsStable); Assert.AreEqual("G", key.GetScaleDegreePitch(a[1], 4).ToString()); Assert.AreEqual(2, a[1].Number); Assert.AreEqual(Alteration.None, a[1].Alteration); Assert.AreEqual(true, a[1].IsStable); Assert.AreEqual("Ab", key.GetScaleDegreePitch(a[2], 4).ToString()); Assert.AreEqual(3, a[2].Number); Assert.AreEqual(Alteration.Lowered, a[2].Alteration); Assert.AreEqual(false, a[2].IsStable); Assert.AreEqual("Bb", key.GetScaleDegreePitch(a[3], 4).ToString()); Assert.AreEqual(4, a[3].Number); Assert.AreEqual(Alteration.None, a[3].Alteration); Assert.AreEqual(true, a[3].IsStable); Assert.AreEqual("C", key.GetScaleDegreePitch(a[4], 4).ToString()); Assert.AreEqual(5, a[4].Number); Assert.AreEqual(Alteration.None, a[4].Alteration); Assert.AreEqual(false, a[4].IsStable); Assert.AreEqual("Db", key.GetScaleDegreePitch(a[5], 4).ToString()); Assert.AreEqual(6, a[5].Number); Assert.AreEqual(Alteration.Lowered, a[5].Alteration); Assert.AreEqual(true, a[5].IsStable); Assert.AreEqual("Eb", key.GetScaleDegreePitch(a[6], 4).ToString()); Assert.AreEqual(7, a[6].Number); Assert.AreEqual(Alteration.Lowered, a[6].Alteration); Assert.AreEqual(false, a[6].IsStable); }
public void Add(ScaleDegree degree) { this.pattern.Add(degree); }
/// <summary> /// Is the given ScaleDegree a third apart from this ScaleDegree? /// </summary> /// <param name="left">The left ScaleDegree for comparison</param> /// <param name="right">The right ScaleDegree for comparison</param> /// <returns>Whether the scale degrees are a third apart or not</returns> public static bool IsThirdWith(this ScaleDegree left, ScaleDegree right) { return(Math.Abs((int)left - (int)right) == 2); }
public void Add(ScaleDegree i) { this.pattern.Add(i); }
public void AlterationException2() { ScaleDegree d = new ScaleDegree(1, (Alteration)(-1)); }
public void AlterationException1() { ScaleDegree d = new ScaleDegree(1, (Alteration)5); }
public void NumberException2() { ScaleDegree d = new ScaleDegree(); d.Number = 8; }
// 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); }
public void ConstructorNumberException() { ScaleDegree d = new ScaleDegree(8, Alteration.None); }