{
"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
}