diff --git a/CHANGELOG.md b/CHANGELOG.md index 7dcfbea..4089805 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ All notable changes to PyTheory are documented here. +## 0.36.5 + +- **Duration arithmetic** — `Duration.WHOLE * 2`, `Duration.HALF + Duration.QUARTER`, + division, and reverse multiply all work now (previously raised TypeError) + ## 0.36.3 - **`Part.hold()`** — polyphonic overlap on a single part. Add notes diff --git a/pyproject.toml b/pyproject.toml index a5af92b..415bfdf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "pytheory" -version = "0.36.4" +version = "0.36.5" description = "Music Theory for Humans" readme = "README.md" license = "MIT" diff --git a/pytheory/__init__.py b/pytheory/__init__.py index dfc615c..b503552 100644 --- a/pytheory/__init__.py +++ b/pytheory/__init__.py @@ -1,6 +1,6 @@ """PyTheory: Music Theory for Humans.""" -__version__ = "0.36.4" +__version__ = "0.36.5" from .tones import Tone, Interval from .systems import System, SYSTEMS, TET diff --git a/pytheory/rhythm.py b/pytheory/rhythm.py index a5d9b9e..096e3f2 100644 --- a/pytheory/rhythm.py +++ b/pytheory/rhythm.py @@ -388,6 +388,24 @@ class Duration(Enum): DOTTED_QUARTER = 1.5 TRIPLET_QUARTER = 2 / 3 + # Arithmetic — lets you write ``Duration.WHOLE * 2`` → 8.0 beats. + def __mul__(self, other): + return self.value * other + + def __rmul__(self, other): + return self.value * other + + def __truediv__(self, other): + return self.value / other + + def __add__(self, other): + if isinstance(other, Duration): + return self.value + other.value + return self.value + other + + def __radd__(self, other): + return other + self.value + class TimeSignature: """A musical time signature like 4/4 or 6/8.""" diff --git a/test_pytheory.py b/test_pytheory.py index 3d518e2..4beb2ba 100644 --- a/test_pytheory.py +++ b/test_pytheory.py @@ -4869,6 +4869,19 @@ def test_duration_values(): assert abs(Duration.TRIPLET_QUARTER.value - 2 / 3) < 1e-9 +def test_duration_arithmetic(): + # Multiplication + assert Duration.WHOLE * 2 == 8.0 + assert 2 * Duration.HALF == 4.0 + assert Duration.QUARTER * 3 == 3.0 + # Division + assert Duration.WHOLE / 2 == 2.0 + # Addition + assert Duration.HALF + Duration.QUARTER == 3.0 + assert Duration.HALF + 1.0 == 3.0 + assert 1.0 + Duration.HALF == 3.0 + + def test_time_signature_from_string_4_4(): ts = TimeSignature.from_string("4/4") assert ts.beats == 4 diff --git a/uv.lock b/uv.lock index 4ba03d4..5205f7d 100644 --- a/uv.lock +++ b/uv.lock @@ -698,7 +698,7 @@ wheels = [ [[package]] name = "pytheory" -version = "0.36.4" +version = "0.36.5" source = { editable = "." } dependencies = [ { name = "numeral" },