{ "cells": [ { "cell_type": "markdown", "id": "466074e1", "metadata": {}, "source": [ "# Guess Scale or Chord from Notes\n", "\n", "The music theory encoded in OMusic allows for some interesting applications. For example, `omusic.guesser.guess` takes a set of notes, then guesses which scale of chords the notes may be from." ] }, { "cell_type": "code", "execution_count": 11, "id": "0354aadb", "metadata": {}, "outputs": [], "source": [ "import random\n", "random.seed(44313)\n", "from omusic.guesser import guess, tabulate_guess\n", "from omusic.guesser import TEST_SCALES, TEST_SCALES_STANDARD" ] }, { "cell_type": "markdown", "id": "e0795076", "metadata": {}, "source": [ "Note that `guess` takes two arguments: (a) a set of note names and (b) scales and chords to test against.\n", "\n", "The module comes with several options for the latter:\n", "\n", "| Option | Included |\n", "| - | - |\n", "| `TEST_SCALES_STANDARD` | Major and minor |\n", "| `TEST_SCALES_MINORS` | Natural, harmonic, and melodic minors |\n", "| `TEST_SCALES_EXPANDED` | Augmented, diminished, pentatonic, and blues |\n", "| `TEST_SCALES_EXPANDED` | Augmented, diminished, pentatonic, and blues |\n", "| `TEST_SCALES_MODES` | From Ionian to Locrian |\n", "| `TEST_CHORDS` | The (1, 3, 5) triad and sevenths |\n", "| `TEST_SCALES` | Every scale. Probably has perfect matches for everything. |\n", "\n", "Try not to use scales and `TEST_CHORDS` together: because scales are larger, the default sorting criteria will prioritise them. Consider using `sort_key=matched_percent` instead." ] }, { "cell_type": "markdown", "id": "f8a6c0ca", "metadata": {}, "source": [ "Suppose we are transcribe a song with \"G\", \"E\", and \"C#\". Call guess, then tabulate the result:" ] }, { "cell_type": "code", "execution_count": 12, "id": "eb42c1ec", "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "
Base Mode Matched Unused Unmatched
C diminished, half whole{'C#', 'G', 'E'}{'A#', 'D#', 'F#', 'C', 'A'}set()
C# diminished, whole half{'C#', 'G', 'E'}{'A#', 'D#', 'F#', 'C', 'A'}set()
C# diminished, half whole{'C#', 'G', 'E'}{'A#', 'B', 'D', 'F', 'G#'} set()
C# blues minor {'C#', 'G', 'E'}{'G#', 'B', 'F#'} set()
C# locrian {'C#', 'G', 'E'}{'D', 'A', 'B', 'F#'} set()
D major {'C#', 'G', 'E'}{'D', 'A', 'B', 'F#'} set()
D harmonic minor {'C#', 'G', 'E'}{'D', 'A', 'F', 'A#'} set()
D melodic minor {'C#', 'G', 'E'}{'D', 'A', 'F', 'B'} set()
D diminished, whole half{'C#', 'G', 'E'}{'A#', 'B', 'D', 'F', 'G#'} set()
D ionian {'C#', 'G', 'E'}{'D', 'A', 'B', 'F#'} set()
" ], "text/plain": [ "'\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n
Base Mode Matched Unused Unmatched
C diminished, half whole{'C#', 'G', 'E'}{'A#', 'D#', 'F#', 'C', 'A'}set()
C# diminished, whole half{'C#', 'G', 'E'}{'A#', 'D#', 'F#', 'C', 'A'}set()
C# diminished, half whole{'C#', 'G', 'E'}{'A#', 'B', 'D', 'F', 'G#'} set()
C# blues minor {'C#', 'G', 'E'}{'G#', 'B', 'F#'} set()
C# locrian {'C#', 'G', 'E'}{'D', 'A', 'B', 'F#'} set()
D major {'C#', 'G', 'E'}{'D', 'A', 'B', 'F#'} set()
D harmonic minor {'C#', 'G', 'E'}{'D', 'A', 'F', 'A#'} set()
D melodic minor {'C#', 'G', 'E'}{'D', 'A', 'F', 'B'} set()
D diminished, whole half{'C#', 'G', 'E'}{'A#', 'B', 'D', 'F', 'G#'} set()
D ionian {'C#', 'G', 'E'}{'D', 'A', 'B', 'F#'} set()
'" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tabulate_guess(guess({\"G\", \"E\", \"C#\"},\n", " TEST_SCALES)[:10],\n", " tablefmt=\"html\")" ] }, { "cell_type": "markdown", "id": "f33a6e38", "metadata": {}, "source": [ "There are several good matches; half whole diminished C is unlikely to be the answer. Time to use your discretion: if the song sounds like a major, try to match for major and minor scales only:" ] }, { "cell_type": "code", "execution_count": 13, "id": "fbd1be89", "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "
Base Mode Matched Unused Unmatched
D major {'C#', 'G', 'E'}{'D', 'A', 'B', 'F#'} set()
B minor {'C#', 'G', 'E'}{'D', 'A', 'B', 'F#'} set()
C major {'G', 'E'} {'B', 'D', 'F', 'C', 'A'} {'C#'}
C# minor {'C#', 'E'} {'D#', 'B', 'F#', 'G#', 'A'}{'G'}
D minor {'G', 'E'} {'A#', 'D', 'F', 'C', 'A'} {'C#'}
E major {'C#', 'E'} {'D#', 'B', 'F#', 'G#', 'A'}{'G'}
E minor {'G', 'E'} {'B', 'F#', 'D', 'C', 'A'} {'C#'}
F major {'G', 'E'} {'A#', 'D', 'F', 'C', 'A'} {'C#'}
F minor {'C#', 'G'} {'A#', 'D#', 'F', 'C', 'G#'}{'E'}
F# minor {'C#', 'E'} {'B', 'F#', 'D', 'G#', 'A'} {'G'}
" ], "text/plain": [ "'\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n
Base Mode Matched Unused Unmatched
D major {'C#', 'G', 'E'}{'D', 'A', 'B', 'F#'} set()
B minor {'C#', 'G', 'E'}{'D', 'A', 'B', 'F#'} set()
C major {'G', 'E'} {'B', 'D', 'F', 'C', 'A'} {'C#'}
C# minor {'C#', 'E'} {'D#', 'B', 'F#', 'G#', 'A'}{'G'}
D minor {'G', 'E'} {'A#', 'D', 'F', 'C', 'A'} {'C#'}
E major {'C#', 'E'} {'D#', 'B', 'F#', 'G#', 'A'}{'G'}
E minor {'G', 'E'} {'B', 'F#', 'D', 'C', 'A'} {'C#'}
F major {'G', 'E'} {'A#', 'D', 'F', 'C', 'A'} {'C#'}
F minor {'C#', 'G'} {'A#', 'D#', 'F', 'C', 'G#'}{'E'}
F# minor {'C#', 'E'} {'B', 'F#', 'D', 'G#', 'A'} {'G'}
'" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tabulate_guess(guess({\"G\", \"E\", \"C#\"},\n", " TEST_SCALES_STANDARD)[:10],\n", " tablefmt=\"html\")" ] }, { "cell_type": "markdown", "id": "7e385865", "metadata": {}, "source": [ "Looks like D is the answer!" ] } ], "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 }