Skip to content

TimeSignature

time_signature

Time signature parsing.

The TimeSignature namespace parses time signature strings into TimeSignature dataclasses with the upper number, lower number, type classification (simple/compound/irregular/irrational), and additive components.

Supported notation:

  • Simple: "4/4", "3/4", "2/2" (denominators 2 or 4).
  • Compound: "6/8", "9/8", "12/8" (denominator 8 with upper divisible by 3).
  • Additive: "3+2+3/8" (groupings sum to upper).
  • Irregular: any other power-of-2 denominator (e.g. "5/16").
  • Irrational: non-power-of-2 denominator (e.g. "4/3").
Example

from tonal_py import TimeSignature ts = TimeSignature.get("4/4") ts.upper, ts.lower, ts.type (4, 4, 'simple') TimeSignature.get("3+2+3/8").additive (3, 2, 3)

Source parity: @tonaljs/time-signature

Robust to garbage

Tonal.js crashes on T.TimeSignature.get("garbage"). Our port returns NO_TIME_SIGNATURE instead.

names

names() -> list[str]

Return common time signature names.

Example

from tonal_py import TimeSignature TimeSignature.names() ['4/4', '3/4', '2/4', '2/2', '12/8', '9/8', '6/8', '3/8']

Source code in src/tonal_py/time_signature.py
def names() -> list[str]:
    """Return common time signature names.

    Example:
        >>> from tonal_py import TimeSignature
        >>> TimeSignature.names()
        ['4/4', '3/4', '2/4', '2/2', '12/8', '9/8', '6/8', '3/8']
    """
    return _NAMES.copy()

parse

parse(literal: Any) -> tuple[Any, int]

Tokenize a time signature literal into (upper, lower).

upper is an int when no additive (+); a list of ints when additive ('3+2+3' -> [3, 2, 3]). lower is always an int.

Parameters:

Name Type Description Default
literal Any

A time signature string or a (upper_str, lower_str) tuple.

required

Returns:

Type Description
tuple[Any, int]

(upper, lower).

Example

from tonal_py import TimeSignature TimeSignature.parse("4/4") (4, 4) TimeSignature.parse("3+2+3/8") ([3, 2, 3], 8)

Source code in src/tonal_py/time_signature.py
def parse(literal: Any) -> tuple[Any, int]:
    """Tokenize a time signature literal into `(upper, lower)`.

    `upper` is an int when no additive (`+`); a `list` of ints when
    additive (`'3+2+3' -> [3, 2, 3]`). `lower` is always an int.

    Args:
        literal: A time signature string or a `(upper_str, lower_str)`
            tuple.

    Returns:
        `(upper, lower)`.

    Example:
        >>> from tonal_py import TimeSignature
        >>> TimeSignature.parse("4/4")
        (4, 4)
        >>> TimeSignature.parse("3+2+3/8")
        ([3, 2, 3], 8)
    """
    if isinstance(literal, str):
        m = _REGEX.match(literal)
        if not m:
            return parse(("", ""))
        return parse((m.group(1), m.group(2)))
    up, down = literal[0], literal[1]
    try:
        denominator = int(down)
    except (ValueError, TypeError):
        denominator = 0
    if isinstance(up, (int, float)) and not isinstance(up, bool):
        return (int(up), denominator)
    if not isinstance(up, str):
        return (0, denominator)
    parts = up.split("+")
    try:
        nums = [int(n) for n in parts]
    except ValueError:
        return (0, denominator)
    if len(nums) == 1:
        return (nums[0], denominator)
    return (nums, denominator)

get

get(literal: Any) -> TimeSignature

Parse and classify a time signature.

Parameters:

Name Type Description Default
literal Any

A time signature string ("4/4", "3+2+3/8").

required

Returns:

Type Description
TimeSignature

A TimeSignature dataclass. Returns NO_TIME_SIGNATURE for

TimeSignature

invalid input (unlike tonal.js, which crashes).

Example

from tonal_py import TimeSignature ts = TimeSignature.get("6/8") ts.type 'compound' ts.upper 6 TimeSignature.get("garbage").empty True

Source code in src/tonal_py/time_signature.py
def get(literal: Any) -> TimeSignature:
    """Parse and classify a time signature.

    Args:
        literal: A time signature string (`"4/4"`, `"3+2+3/8"`).

    Returns:
        A `TimeSignature` dataclass. Returns `NO_TIME_SIGNATURE` for
        invalid input (unlike tonal.js, which crashes).

    Example:
        >>> from tonal_py import TimeSignature
        >>> ts = TimeSignature.get("6/8")
        >>> ts.type
        'compound'
        >>> ts.upper
        6
        >>> TimeSignature.get("garbage").empty
        True
    """
    key = repr(literal)
    cached = _CACHE.get(key)
    if cached is not None:
        return cached  # type: ignore[return-value]
    ts = _build(parse(literal))
    _CACHE[key] = ts
    return ts