{ "cells": [ { "cell_type": "code", "execution_count": null, "id": "45088930", "metadata": {}, "outputs": [], "source": [ "import automuse\n", "import automuse.scale as scale\n", "import automuse.modes as modes\n", "import automuse.transforms as transforms" ] }, { "cell_type": "markdown", "id": "eca2ba9e", "metadata": {}, "source": [ "# Transforms\n", "\n", "Transforms in music map between sets of notes. From simple triad inversions to Neo-Riemannian [^1] processes, all transforms share one common purpose: to discover alternative, possibly more interesting, expressions.\n", "\n", "To take from your hand the burden of doing actual music, AutoMuse implements some of these transforms.\n", "\n", "[^1]: Not _that_ Riemann, for you math people out there." ] }, { "cell_type": "markdown", "id": "9323217e", "metadata": {}, "source": [ "### Inverting Intervals\n", "\n", "To **invert** a group of notes is to move the lowest note an octave higher. This is easy to implement.\n", "\n", "Inverting an interval carries a related meaning. Suppose that inverting C-G gives G-C: _inverting the interval_ between C-G should yield the interval between G-C. The `invert_interval` function captures this behaviour." ] }, { "cell_type": "markdown", "id": "3d417a68", "metadata": {}, "source": [ "Perfect intervals always invert to perfect intervals. A factoid: inverting the perfect 4th and the perfect 5th give each other." ] }, { "cell_type": "code", "execution_count": 2, "id": "e24094f8", "metadata": {}, "outputs": [], "source": [ "assert transforms.invert(automuse.INTERVALS[\"perfect 5\"])\\\n", " == automuse.INTERVALS[\"perfect 4\"]\\\n", " and transforms.invert(automuse.INTERVALS[\"perfect 4\"])\\\n", " == automuse.INTERVALS[\"perfect 5\"]" ] }, { "cell_type": "markdown", "id": "ee989f0f", "metadata": {}, "source": [ "Reaching \"up\" from a note by a given interval, then again by the invert of that interval, should produce that note (albeit an octave higher). Together, `reach` and `invert_interval` allows us to test this:" ] }, { "cell_type": "code", "execution_count": 3, "id": "52a2e5e5", "metadata": {}, "outputs": [], "source": [ "from automuse import (same_class,\n", " reach)" ] }, { "cell_type": "code", "execution_count": 4, "id": "000c32f5", "metadata": {}, "outputs": [], "source": [ "for note, interval in zip(automuse.NOTES,\n", " automuse.INTERVALS.values()):\n", " assert same_class(note,\n", " reach(reach(note, interval),\n", " transforms.invert(interval)))" ] }, { "cell_type": "markdown", "id": "e1693656", "metadata": {}, "source": [ "## Transposition\n", "\n", "Transposition moves a set of notes up or down by semitones." ] }, { "cell_type": "code", "execution_count": 5, "id": "2f52b806", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['C#0', 'D#0', 'F0', 'F#0', 'G#0', 'A#0', 'C1']" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "transforms.transpose(scale.scale(\"C\", modes.MAJOR), 1)" ] }, { "cell_type": "markdown", "id": "5c5fd51b", "metadata": {}, "source": [ "## Neo-Riemannian Transforms\n", "\n", "Neo-Riemannian transformations map between harmonies. AutoMuse implements a few.\n", "\n", "Some transformations are implemented with reference to, or checked against, other resources. Please see documentation for attributions." ] }, { "cell_type": "code", "execution_count": 6, "id": "01f60671", "metadata": {}, "outputs": [], "source": [ "from automuse.transforms import\\\n", " (nrt_parallel,\n", " nrt_relative,\n", " nrt_slide,\n", " nrt_leading_tone_exchange,\n", " nrt_near_fifth,\n", " nrt_far_fifth,\n", " nrt_dominant,\n", " nrt_hexatonic_pole,\n", " nrt_t6,)" ] } ], "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 }