{ "cells": [ { "cell_type": "code", "execution_count": 1, "id": "1195e063", "metadata": {}, "outputs": [], "source": [ "import automuse\n", "import automuse.chord as chord\n", "import automuse.scale as scale\n", "import automuse.modes as modes" ] }, { "cell_type": "markdown", "id": "795d388a", "metadata": {}, "source": [ "### Circle of Fifths\n", "\n", "The mythical Circle of Fifths, often found in introductory music theory textbooks, highlights some interesting relation in music. This notebook seeks to explore these.\n", "\n", "To construct the circle, let us keep counting fifths, beginning at $\\mathrm{C}\\$:" ] }, { "cell_type": "code", "execution_count": 2, "id": "213c6554", "metadata": {}, "outputs": [], "source": [ "from automuse import reach" ] }, { "cell_type": "code", "execution_count": 3, "id": "25248fff", "metadata": {}, "outputs": [], "source": [ "def count_fifths(base: str, length: int):\n", " accumulated: list[str] = []\n", " for _ in range(length):\n", " accumulated.append(base)\n", " base = reach(base, \"perfect 5\")\n", " return accumulated\n", " " ] }, { "cell_type": "code", "execution_count": 4, "id": "8f7d576d", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['C0', 'G0', 'D1', 'A1', 'E2', 'B2', 'F#3', 'C#4', 'G#4', 'D#5', 'A#5', 'F6', 'C7']\n" ] } ], "source": [ "exterior_ring: list[str] = count_fifths(\"C0\", 13)\n", "print(exterior_ring)" ] }, { "cell_type": "markdown", "id": "f80147ea", "metadata": {}, "source": [ "Conveniently, counting notes this way gives all 12 notes of an octave, with the 13th note coming back to $\\text{C}$. These 12 notes form a cycle.\n", "\n", "Recall that A is the submediant of C; consequently the Am scale is the relative minor of CM. Let us count another 12 notes, this time starting with A:" ] }, { "cell_type": "code", "execution_count": 5, "id": "2f8123e5", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['A0', 'E1', 'B1', 'F#2', 'C#3', 'G#3', 'D#4', 'A#4', 'F5', 'C6', 'G6', 'D7', 'A7']\n" ] } ], "source": [ "interior_ring: list[str] = count_fifths(\"A0\", 13)\n", "print(interior_ring)" ] }, { "cell_type": "markdown", "id": "b2f6ad78", "metadata": {}, "source": [ "To form the circle of fifth, stack these cycles on top of each other. This is so very isomorphic.\n", "\n", "\n", "\n", "The circle of fifth has many uses. First of all, it matches every chord to its relative major: for every note in the exterior ring, its major scale has the same notes as the minor scale constructed with its interior neighbour:" ] }, { "cell_type": "code", "execution_count": 6, "id": "06a4a1ea", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['C0', 'E0', 'G0']" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "chord.chord(\"C\", modes.MAJOR)" ] }, { "cell_type": "code", "execution_count": 7, "id": "e35679fb", "metadata": {}, "outputs": [], "source": [ "for i in range(len(exterior_ring)):\n", " assert automuse.same_class(\n", " scale.scale(exterior_ring[i], modes.MAJOR),\n", " scale.scale(interior_ring[i], modes.MINOR)\n", " )" ] }, { "cell_type": "markdown", "id": "8384bedd", "metadata": {}, "source": [ "Continue for more uses of the circle." ] }, { "cell_type": "markdown", "id": "b6fd39a0", "metadata": {}, "source": [ "### Usage: Neighbouring Scales\n", "\n", "The circle of fifths is a neat way to arrange scales. The closest (in $\\mathscr{l}_1$) neighbours of a scale are its neighbours on the circle: for example, CM and GM differ by exactly 1 note which differs by exactly 1 semitone; the same is true for GM and DM." ] }, { "cell_type": "code", "execution_count": 8, "id": "579993d3", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['A0', 'B0', 'C0', 'D0', 'E0', 'F0', 'G0']\n", "['A0', 'B0', 'C1', 'D1', 'E1', 'F#1', 'G0']\n", "['A0', 'B0', 'C#1', 'D0', 'E0', 'F#0', 'G0']\n" ] } ], "source": [ "print(sorted(scale.scale(\"C\", modes.MAJOR)))\n", "print(sorted(scale.scale(\"G\", modes.MAJOR)))\n", "print(sorted(scale.scale(\"D\", modes.MAJOR)))" ] }, { "cell_type": "markdown", "id": "0dd914fb", "metadata": {}, "source": [ "## Geometry\n", "\n", "Coincidentally, neighbours of a note are in its major scale: its left neighbour the subdominant ($\\hat{4}$), its right neighbour the dominant ($\\hat{5}$), and its interior neighbour the submediant ($\\hat{6}$).\n", "\n", "\n", "\n", "Because chords are constructed from scale degrees, chords can be expressed on the circle as polygons. For example, connecting notes on a C major triad results in a triangle; rotating this triangle clockwise by $30\\degree$ gives the G major triad.\n", "\n", "\n", "\n", "Tools of this kind are common in music. Another good example is the Tonnetz for visualising Neo-Riemannian transforms. The Tonnetz which will not be explained here." ] }, { "cell_type": "markdown", "id": "1e8eef63", "metadata": {}, "source": [ "## Usage: Sharps and Flats\n", "\n", "Another interesting pattern: starting at C and counting clockwise, each subsequent scale has one more sharp. Going down from C has the same effect: each subsequent scale has one more flat.\n", "\n", "As a result, each note on the circle corresponds to a number of sharps and flats. These accidentals are often notated right after the staff." ] }, { "cell_type": "code", "execution_count": 9, "id": "c120439a", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0\n", "1\n", "2\n", "3\n", "4\n", "5\n", "5\n", "5\n", "4\n", "3\n", "2\n", "1\n" ] } ], "source": [ "for base in count_fifths(\"C0\", 12):\n", " print(len(\n", " [x for x in scale.scale(base, modes.MAJOR)\n", " if \"#\" in x]\n", " ))" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.10" } }, "nbformat": 4, "nbformat_minor": 5 }