Analysis CI Coverage Status style: very good analysis pub package License

A simple Dart library that provides a comprehensive set of utilities for working with music theory concepts through a beautifully crafted API.

Features

  • Chords, harmonic functions, and circle of fifths
  • Intervals and qualities
  • Notes, frequencies, accidentals, and enharmonic operations
  • Scales and scale degrees
  • Keys, key signatures, and modes
  • Tuning systems (work in progress)

Usage

Import the package into your Dart code:

import 'package:music_notes/music_notes.dart';

Now, you can use the provided APIs to perform various music theory operations. For more detailed usage instructions and examples, please refer to the API documentation.

Notes

Define Notes from the musical scale:

Note.c; // C
Note.d; // D
Note.f; // F

Alter them:

Note.c.sharp; // C♯
Note.d.flat; // D♭
Note.g.flat.flat; // G𝄫
Note.f.sharp.sharp.sharp; // F𝄪♯

And position them in the octave, resulting in Pitches:

Note.f.inOctave(4); // F4
Note.b.flat.inOctave(5); // B♭5

Or just parse them in both scientific and Helmholtz notations:

Note.parse('a#'); // A♯
Pitch.parse("g''"); // G5
Pitch.parse('Eb3'); // E♭3

Intervals

Create an Interval:

const Interval.imperfect(Size.tenth, ImperfectQuality.major); // M10
Interval.d5; // d5
Size.sixth.augmented; // A6
Size.eleventh.simple.perfect; // P4

Or turn it descending:

-Interval.m7; // m-7
Interval.M3.descending(); // M-3

Calculate the Interval between two notes:

Note.c.interval(Note.g); // P5
Note.d.interval(Note.f.sharp).inverted; // m6
Note.g.flat.transposeBy(-Interval.m3); // E♭

And even play with the circle of fifths or any circle of intervals up to a distance:

Interval.P5.circleFrom(Note.c, distance: 12).toList();
// [C, G, D, A, E, B, F♯, C♯, G♯, D♯, A♯, E♯, B♯]
Note.c.circleOfFifths();
// (flats: [F, B♭, E♭, A♭, D♭, G♭], sharps: [G, D, A, E, B, F♯])

Keys

Create a Key or get it from a given Note:

const Key(Note.e, TonalMode.minor); // E minor
Note.a.flat.major; // A♭ major

Know its KeySignature:

Note.d.major.signature; // 2 (F♯ C♯)
Note.e.flat.minor.signature; // -6 (B♭ E♭ A♭ D♭ G♭ C♭)

And its relative Key:

Note.d.major.relative; // B minor
Note.c.minor.relative; // E♭ major

Key signatures

Create a KeySignature:

KeySignature.fromDistance(4); // 4 (F♯ C♯ G♯ D♯)
KeySignature([Note.b.flat, Note.e.flat]); // -2 (B♭ E♭)
KeySignature([Note.g.sharp, Note.a.sharp]); // null (G♯ A♯)

And know its Keys:

KeySignature([Note.f.sharp]).keys[TonalMode.major]; // G major
KeySignature.empty.keys[TonalMode.minor]; // A minor

Non-canonical key signatures are also supported, although they return null when asked about their fifths distance or keys:

KeySignature([Note.a.flat])
  ..isCanonical // false
  ..distance // null
  ..keys; // <TonalMode, Key>{}

Modes

Get each Mode’s ScalePattern:

TonalMode.minor.scale; // ScalePattern.minor
ModalMode.locrian.scale; // ScalePattern.locrian

Their Dorian Brightness Quotient:

ModalMode.lydian.brightness; // 3
ModalMode.dorian.brightness; // 0
ModalMode.aeolian.brightness; // -1

Or its mirrored version:

ModalMode.ionian.mirrored; // ModalMode.phrygian
ModalMode.aeolian.mirrored; // ModalMode.mixolydian

Scales

Create a Scale from a ScalePattern:

ScalePattern.lydian.on(Note.d); // D Lydian (D E F♯ G♯ A B C♯ D)
ScalePattern.wholeTone.on(Note.f); // F Whole-tone (F G A B C♯ D♯ F)
ScalePattern.majorPentatonic.on(Note.g.flat);
// G♭ Major pentatonic (G♭ A♭ B♭ D♭ E♭ G♭)

Or get it from a Key:

Note.a.flat.major.scale; // A♭ Major (ionian) (A♭ B♭ C D♭ E♭ F G A♭)
Note.d.minor.scale; // D Natural minor (aeolian) (D E F G A B♭ C D)

Even play with any ScaleDegree or HarmonicFunction:

ScalePattern.lydian.on(Note.e).degree(ScaleDegree.iv); // A♯
Note.c.major.scale.functionChord(
  HarmonicFunction.dominantV / HarmonicFunction.dominantV,
); // D maj. (D F♯ A)

Chords

Create a Chord from a series of Notes or a ChordPattern:

Chord([Note.a, Note.c.sharp, Note.e]); // A maj. (A C♯ E)
ChordPattern.augmentedTriad.add11().add13().on(Note.d.sharp);
// D♯ aug. (D♯ F𝄪 A𝄪 G♯ B♯)

Or build it on top of a Note:

Note.f.minorTriad.add7().add9(ImperfectQuality.minor);
// F min. (F A♭ C E♭ G♭)
Note.e.flat.diminishedTriad.add7().transposeBy(Interval.m2);
// F♭ dim. (F♭ A𝄫 C𝄫 E𝄫)

Or modify its root triad:

Note.g.minorTriad.major; // G maj. (G B D)
Note.f.sharp.majorTriad.add9().diminished; // F♯ dim. (F♯ A C G♯)

Frequencies

Get the Frequency of a Pitch:

Note.a.inOctave(4).frequency(); // 440
Note.b.flat.inOctave(4).frequency(
      referenceFrequency: const Frequency(256),
      tuningSystem:
          EqualTemperament.edo12(referencePitch: Note.c.inOctave(4)),
    ); // 456.1401436878537

Get the closest note from a given Frequency:

const Frequency(432).closestPitch(); // A4-32
const Frequency(314).closestPitch(); // E♭4+16

And combining both methods, the harmonic series of a given Pitch:

Note.c.inOctave(1).harmonics(upToIndex: 15);
// {C1, C2, G2+2, C3, E3-14, G3+2, A♯3-31, C4, D4+4,
// E4-14, F♯4-49, G4+2, A♭4+41, A♯4-31, B4-12, C5}

In a nutshell

ScalePattern.lydian // Lydian (M2 M2 M2 m2 M2 M2 m2)
    .on(Note.parse('a')) // A Lydian (A B C♯ D♯ E F♯ G♯ A)
    .transposeBy(Interval.M2) // B Lydian (B C♯ D♯ E♯ F♯ G♯ A♯ B)
    .degree(ScaleDegree.iii) // D♯
    .respelledUpwards // E♭
    .major // E♭ major
    .relative // C minor
    .scale // C Natural minor (aeolian) (C D E♭ F G A♭ B♭ C)
    .degreeChord(ScaleDegree.v) // G min. (G B♭ D)
    .add9(); // G min. (G B♭ D A)

Inspiration

This library is inspired by a range of music theory projects.

Contributing

Contributions are welcome! If you encounter any issues or have suggestions for improvements, please feel free to open an issue or submit a pull request on the GitHub repository.

Star History

License

This package is released under the BSD-3-Clause License.

Libraries

music_notes
A simple Dart library that provides a comprehensive set of utilities for working with music theory concepts.
utils