concertina_helper.type_defs

  1from __future__ import annotations
  2from collections.abc import Callable, Iterator
  3from dataclasses import dataclass
  4from enum import Enum, auto
  5from typing import Any, Iterable
  6
  7from pyabc2 import Pitch as AbcPitch
  8
  9
 10@dataclass(frozen=True)
 11class Pitch:
 12    '''
 13    Immutable class representing a musical pitch.
 14    '''
 15    name: str
 16
 17    # TODO: post_init validation: fail if name != normalized name
 18
 19    @property
 20    def _pitch(self) -> AbcPitch:
 21        return AbcPitch.from_name(self.name)
 22
 23    @property
 24    def class_name(self) -> str:
 25        return self._pitch.class_name
 26
 27    def transpose(self, semitones: int) -> Pitch:
 28        return Pitch(AbcPitch(self._pitch.value + semitones).name)
 29
 30    def __str__(self) -> str:
 31        return self.name
 32
 33    def __eq__(self, other: Any) -> bool:
 34        if type(self) != type(other):
 35            raise TypeError('mixed operand types')
 36        return self._pitch.value == other._pitch.value
 37
 38
 39@dataclass(frozen=True)
 40class PitchMatrix:
 41    '''
 42    Represents the pitches that can be produced by one half of a concertina,
 43    on either the push or pull, if bisonoric.
 44    '''
 45    matrix: tuple[tuple[Pitch, ...], ...]
 46
 47    def transpose(self, semitones: int) -> PitchMatrix:
 48        return PitchMatrix(
 49            tuple(
 50                tuple(
 51                    proxy.transpose(semitones)
 52                    for proxy in row
 53                )
 54                for row in self.matrix
 55            )
 56        )
 57
 58    def __getitem__(self, i: int) -> tuple[Pitch, ...]:
 59        return self.matrix[i]
 60
 61    def __iter__(self) -> Iterator[tuple[Pitch, ...]]:
 62        return iter(self.matrix)
 63
 64
 65@dataclass(frozen=True)
 66class Mask:
 67    '''
 68    A boolean matix. `True` represents a key held down.
 69
 70    >>> Mask(((True, False),)) | Mask(((False, True),))
 71    Mask(bool_matrix=((True, True),))
 72    '''
 73    bool_matrix: tuple[tuple[bool, ...], ...]
 74
 75    @property
 76    def shape(self) -> Iterable[int]:
 77        return [len(row) for row in self.bool_matrix]
 78
 79    def __getitem__(self, i: int) -> tuple[bool, ...]:
 80        return self.bool_matrix[i]
 81
 82    def __iter__(self) -> Iterator[tuple[bool, ...]]:
 83        return iter(self.bool_matrix)
 84
 85    def __or__(self, other: Any) -> Mask:
 86        if type(self) != type(other):
 87            raise TypeError('mixed operand types')
 88        if self.shape != other.shape:
 89            raise ValueError('different shapes')
 90        return Mask(
 91            tuple(
 92                tuple(
 93                    self_bool or other_bool
 94                    for self_bool, other_bool
 95                    in zip(self_row, other_row)
 96                )
 97                for self_row, other_row
 98                in zip(self, other)
 99            )
100        )
101
102
103Shape = tuple[Iterable[int], Iterable[int]]
104'''
105Describes the button arrangement of an instrument:
106respectively the left and right faces, and for each face,
107the number of buttons in each row.
108'''
109
110PitchToStr = Callable[[Pitch], str]
111'''
112A function which takes a pitch and returns a string.
113(Should the octave number be printed?
114Should unicode characters be used for accidentals?
115Those sort of details are handled by the function.)
116'''
117
118
119class Direction(Enum):
120    '''
121    `PUSH` and `PULL`are paired with a unisonoric fingering
122    to create a bisonoric fingering
123    '''
124    PUSH = auto()
125    PULL = auto()
126
127    def __repr__(self) -> str:
128        return f'Direction.{self.name}'
129
130
131@dataclass(frozen=True, kw_only=True)
132class Annotation:
133    pitch: Pitch
134    measure: int
@dataclass(frozen=True)
class Pitch:
11@dataclass(frozen=True)
12class Pitch:
13    '''
14    Immutable class representing a musical pitch.
15    '''
16    name: str
17
18    # TODO: post_init validation: fail if name != normalized name
19
20    @property
21    def _pitch(self) -> AbcPitch:
22        return AbcPitch.from_name(self.name)
23
24    @property
25    def class_name(self) -> str:
26        return self._pitch.class_name
27
28    def transpose(self, semitones: int) -> Pitch:
29        return Pitch(AbcPitch(self._pitch.value + semitones).name)
30
31    def __str__(self) -> str:
32        return self.name
33
34    def __eq__(self, other: Any) -> bool:
35        if type(self) != type(other):
36            raise TypeError('mixed operand types')
37        return self._pitch.value == other._pitch.value

Immutable class representing a musical pitch.

Pitch(name: str)
def transpose(self, semitones: int) -> concertina_helper.type_defs.Pitch:
28    def transpose(self, semitones: int) -> Pitch:
29        return Pitch(AbcPitch(self._pitch.value + semitones).name)
@dataclass(frozen=True)
class PitchMatrix:
40@dataclass(frozen=True)
41class PitchMatrix:
42    '''
43    Represents the pitches that can be produced by one half of a concertina,
44    on either the push or pull, if bisonoric.
45    '''
46    matrix: tuple[tuple[Pitch, ...], ...]
47
48    def transpose(self, semitones: int) -> PitchMatrix:
49        return PitchMatrix(
50            tuple(
51                tuple(
52                    proxy.transpose(semitones)
53                    for proxy in row
54                )
55                for row in self.matrix
56            )
57        )
58
59    def __getitem__(self, i: int) -> tuple[Pitch, ...]:
60        return self.matrix[i]
61
62    def __iter__(self) -> Iterator[tuple[Pitch, ...]]:
63        return iter(self.matrix)

Represents the pitches that can be produced by one half of a concertina, on either the push or pull, if bisonoric.

PitchMatrix(matrix: tuple[tuple[concertina_helper.type_defs.Pitch, ...], ...])
def transpose(self, semitones: int) -> concertina_helper.type_defs.PitchMatrix:
48    def transpose(self, semitones: int) -> PitchMatrix:
49        return PitchMatrix(
50            tuple(
51                tuple(
52                    proxy.transpose(semitones)
53                    for proxy in row
54                )
55                for row in self.matrix
56            )
57        )
@dataclass(frozen=True)
class Mask:
 66@dataclass(frozen=True)
 67class Mask:
 68    '''
 69    A boolean matix. `True` represents a key held down.
 70
 71    >>> Mask(((True, False),)) | Mask(((False, True),))
 72    Mask(bool_matrix=((True, True),))
 73    '''
 74    bool_matrix: tuple[tuple[bool, ...], ...]
 75
 76    @property
 77    def shape(self) -> Iterable[int]:
 78        return [len(row) for row in self.bool_matrix]
 79
 80    def __getitem__(self, i: int) -> tuple[bool, ...]:
 81        return self.bool_matrix[i]
 82
 83    def __iter__(self) -> Iterator[tuple[bool, ...]]:
 84        return iter(self.bool_matrix)
 85
 86    def __or__(self, other: Any) -> Mask:
 87        if type(self) != type(other):
 88            raise TypeError('mixed operand types')
 89        if self.shape != other.shape:
 90            raise ValueError('different shapes')
 91        return Mask(
 92            tuple(
 93                tuple(
 94                    self_bool or other_bool
 95                    for self_bool, other_bool
 96                    in zip(self_row, other_row)
 97                )
 98                for self_row, other_row
 99                in zip(self, other)
100            )
101        )

A boolean matix. True represents a key held down.

>>> Mask(((True, False),)) | Mask(((False, True),))
Mask(bool_matrix=((True, True),))
Mask(bool_matrix: tuple[tuple[bool, ...], ...])
Shape = tuple[typing.Iterable[int], typing.Iterable[int]]

Describes the button arrangement of an instrument: respectively the left and right faces, and for each face, the number of buttons in each row.

PitchToStr = collections.abc.Callable[[concertina_helper.type_defs.Pitch], str]

A function which takes a pitch and returns a string. (Should the octave number be printed? Should unicode characters be used for accidentals? Those sort of details are handled by the function.)

class Direction(enum.Enum):
120class Direction(Enum):
121    '''
122    `PUSH` and `PULL`are paired with a unisonoric fingering
123    to create a bisonoric fingering
124    '''
125    PUSH = auto()
126    PULL = auto()
127
128    def __repr__(self) -> str:
129        return f'Direction.{self.name}'

PUSH and PULLare paired with a unisonoric fingering to create a bisonoric fingering

Inherited Members
enum.Enum
name
value
@dataclass(frozen=True, kw_only=True)
class Annotation:
132@dataclass(frozen=True, kw_only=True)
133class Annotation:
134    pitch: Pitch
135    measure: int
Annotation(*, pitch: concertina_helper.type_defs.Pitch, measure: int)