Skip to content

chords

JustLatticeChord

This class implements chords based on lattice coordinates.

Source code in /opt/hostedtoolcache/Python/3.11.3/x64/lib/python3.11/site-packages/jintonic/chords.py
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
class JustLatticeChord:
    """This class implements chords based on lattice coordinates."""

    def __init__(
        self,
        fundamental: float,
        root: List[int],
        nodes: List[List[int]],
    ):
        """Initializes a JustLatticeChord.

        Parameters:
            fundamental: Fundamental pitch in Hertz.
            root: Root lattice node (the chord's root tone)
            nodes: Lattice nodes of each constituent chord tone.

        Examples:
            >>> nodes = [[-1, 0, 1], [1, 0, 0], [0, 0, 1]]
            >>> JustLatticeChord(fundamental=100.0, root=[1, 0, 0], nodes=nodes)
            JustLatticeChord(100.0 Hz, [3/2, 7/4, 9/8, 21/16], [3-7-9-21])
        """
        self._fundamental: float = float(fundamental)
        self._nodes = nodes
        self._root = root
        self.lattice = JustLattice(fundamental=self._fundamental)

    @classmethod
    def from_name(
        cls,
        fundamental: float,
        root: List[int],
        name: str,
    ) -> JustLatticeChord:
        """Initializes a JustLatticeChord from a conventional chord name.

        Parameters:
            fundamental: The fundamental frequency in Hertz
            root: The root node lattice coordinates
            name: The chord name

        Returns:
            A JustLatticeChord

        The list of valid names is:
            - "sub-minor triad"
            - "minor triad"
            - "diminished triad"
            - "major triad"
            - "sub-minor seventh"
            - "minor seventh"
            - "half-diminished seventh"
            - "major seventh"
            - "super-major seventh"
            - "dominant seventh"
            - "added second"
            - "minor ninth"
            - "major ninth"
            - "dominant ninth"
            - "4-6-7"
            - "5-7-9"

        Examples:

            >>> JustLatticeChord.from_name(60, [0, 0, 0], 'minor triad')
            JustLatticeChord(60.0 Hz, [1/1, 6/5, 3/2], [5-3-15])

            >>> JustLatticeChord.from_name(60, [-1, 0, 0], 'major triad')
            JustLatticeChord(60.0 Hz, [4/3, 5/3, 1/1], [1-5-3])
        """
        nodes = {
            "sub-minor triad": [[1, 0, 0], [-1, 0, 1]],
            "minor triad": [[1, -1, 0], [1, 0, 0]],
            "diminished triad": [[1, -1, 0], [0, -1, 1]],
            "major triad": [[0, 1, 0], [1, 0, 0]],
            "sub-minor seventh": [[-1, 0, 1], [1, 0, 0], [0, 0, 1]],
            "minor seventh": [[1, -1, 0], [1, 0, 0], [2, -1, 0]],
            "half-diminished seventh": [[1, -1, 0], [0, -1, 1], [2, -1, 0]],
            "major seventh": [[0, 1, 0], [1, 0, 0], [1, 1, 0]],
            "super-major seventh": [[2, 0, -1], [1, 0, 0], [3, 0, -1]],
            "dominant seventh": [[0, 1, 0], [1, 0, 0], [1, 1, 0], [0, 0, 1]],
            "added second": [[0, 1, 0], [1, 0, 0], [2, -1, 0]],
            "minor ninth": [[1, -1, 0], [1, 0, 0], [2, -1, 0], [2, 0, 0]],
            "major ninth": [[0, 1, 0], [1, 0, 0], [1, 1, 0], [2, 0, 0]],
            "dominant ninth": [[0, 1, 0], [1, 0, 0], [0, 0, 1], [2, 0, 0]],
            "4-6-7": [[1, 0, 0], [0, 0, 1]],
            "5-7-9": [[0, -1, 1], [2, -1, 0]],
        }
        try:
            return cls(fundamental, root, nodes[name.lower()])
        except KeyError:
            return NotImplemented

    def transpose(self, node: List[int]) -> JustLatticeChord:
        """JustLatticeChord transposition.

        Parameters:
            node: The target root node of the transposed chord.

        Returns:
            A transposed JustLatticeChord

        Note:
            Returns a copy

        Examples:
            >>> chord = JustLatticeChord.from_name(60, [0, 0, 0], 'minor triad')
            >>> node = [1, 0, 0]
            >>> chord.transpose(node)
            JustLatticeChord(60.0 Hz, [3/2, 9/5, 9/8], [5-3-15])
        """
        chord = deepcopy(self)
        chord.root = node
        chord.lattice.to_node((node))

        return chord

    def pivot(self, axis: int = 3) -> JustLatticeChord:
        """Pivots the JustLatticeChord along the given axis.

        Parameters:
            axis: Prime limit axis (a prime number)

        Returns:
            A pivoted JustLatticeChord

        Note:
            Returns a copy

        Examples:
            >>> chord = JustLatticeChord.from_name(60, [0, 0, 0], 'major triad')
            >>> chord.pivot(3)
            JustLatticeChord(60.0 Hz, [1/1, 5/4, 4/3], [3-15-1])
        """
        if axis > self.prime_limit:
            raise ValueError(
                "Cannot pivot on an axis greater than the chord's prime limit."
            )
        chord = deepcopy(self)
        axis_ix = generate_primes(chord.prime_limit)[1:].index(axis)
        base = min(node[axis_ix] for node in chord._nodes)
        base = 0
        for i, node in enumerate(chord._nodes):
            node[axis_ix] = base - node[axis_ix]
            chord._nodes[i] = node
        return chord

    @property
    def fundamental(self):
        return self._fundamental

    @property
    def nodes(self):
        """JustLatticeChord nodes."""
        return self._nodes

    @nodes.setter
    def nodes(self, values: List[List[int]]):
        """JustLatticeChord nodes.

        Parameters:
            values: Constituent lattice nodes.
        """
        """Sets (and expands) JustLatticeChord nodes."""
        max_len = max((len(node) for node in values))
        self._nodes = []
        for node in values:
            self._nodes.append(node + (max_len - len(node)) * [0])

    @property
    def root(self):
        """JustLatticeChord root node."""
        return self._root

    @root.setter
    def root(self, value: List[int]):
        """Sets (and expands) JustLatticeChord root node.

        Parameters:
            value: Root lattice node
        """
        max_len = max((len(node) for node in self._nodes))
        self._root = value + (max_len - len(value)) * [0]

    @property
    def tones(self) -> List[JustInterval]:
        """JustLatticeChord constituent intervals from root (tones).

        Returns:
            The tones of the chord as JustIntervals from the fundamental.

        Examples:
            >>> chord = JustLatticeChord.from_name(60, [0, 0, 0], 'major triad')
            >>> chord.tones
            [JustInterval(1, 1), JustInterval(5, 4), JustInterval(3, 2)]
        """
        tones = []
        self.lattice.to_node(self._root)
        root_tone = self.lattice.tone
        tones.append(root_tone)
        for node in self._nodes:
            self.lattice.to_node(self._root)
            constituent = self.lattice.traverse(node)
            constituent_tone = constituent.tone
            tones.append(constituent_tone)
        self.lattice.to_node(self._root)

        return tones

    @property
    def prime_limit(self) -> int:
        """JustLatticeChord prime limit."""
        return max([tone.prime_limit for tone in self.tones])

    @property
    def harmonics(self) -> List[int]:
        """JustLatticeChord harmonics (relative frequencies).

        Returns:
            The lattice's prime limit

        Examples:
            >>> chord = JustLatticeChord.from_name(60, [0, 0, 0], 'minor triad')
            >>> chord.harmonics
            [10, 12, 15]
        """
        return tones_to_harmonic_segment(self.tones)

    @property
    def identities(self) -> List[int]:
        """JustLatticeChord constituent identities.

        Returns:
            The constituent identities

        Examples:
            >>> chord = JustLatticeChord.from_name(60, [0, 0, 0], 'minor triad')
            >>> chord.identities
            [5, 3, 15]
        """
        return harmonic_segment_to_identities(self.harmonics)

    @property
    def hertz(self) -> List[float]:
        """JustLatticeChord constituent Hertz values.

        Returns:
            The frequencies in Hertz of the constituent pitches

        Examples:
            >>> chord = JustLatticeChord.from_name(60, [0, 0, 0], 'minor triad')
            >>> chord.hertz
            [60.0, 72.0, 90.0]
        """
        tones = [self.tones[0]]
        for tone in self.tones[1:]:
            while tone < tones[-1]:
                tone += JustInterval(2, 1)
            tones.append(tone)
        return [self._fundamental * tone for tone in tones]

    @property
    def complement(self) -> JustLatticeChord:
        """JustLatticeChord complement.

        Every node's relationship to the root node is inverted.

        Returns:
            A JustLatticeChord that is the complement of this one

        Note:
            Returns a copy.

        Examples:
            >>> nodes = [[2, 0], [0, 1], [-1, 0], [1, 0]]
            >>> chord = JustLatticeChord(60, [0, 0, 0], nodes)
            >>> chord.complement
            JustLatticeChord(60.0 Hz, [1/1, 16/9, 8/5, 3/2, 4/3], [45-5-9-135-15])
        """
        nodes = []
        for node in self._nodes:
            nodes.append(list(map(lambda x, y: y - x, node, self._root)))
        return JustLatticeChord(self._fundamental, self._root, nodes)

    def __repr__(self):
        """repr(self)"""
        tones = ", ".join(
            [
                "/".join([str(tone.numerator), str(tone.denominator)])
                for tone in self.tones
            ]
        )
        identities = ", ".join(
            ["-".join([str(identity) for identity in self.identities])]
        )
        return "{}({} Hz, [{}], [{}])".format(
            self.__class__.__name__, self._fundamental, tones, identities
        )

prime_limit: int property

JustLatticeChord prime limit.

tones: List[JustInterval] property

JustLatticeChord constituent intervals from root (tones).

Returns:

Type Description
List[JustInterval]

The tones of the chord as JustIntervals from the fundamental.

Examples:

>>> chord = JustLatticeChord.from_name(60, [0, 0, 0], 'major triad')
>>> chord.tones
[JustInterval(1, 1), JustInterval(5, 4), JustInterval(3, 2)]

hertz: List[float] property

JustLatticeChord constituent Hertz values.

Returns:

Type Description
List[float]

The frequencies in Hertz of the constituent pitches

Examples:

>>> chord = JustLatticeChord.from_name(60, [0, 0, 0], 'minor triad')
>>> chord.hertz
[60.0, 72.0, 90.0]

harmonics: List[int] property

JustLatticeChord harmonics (relative frequencies).

Returns:

Type Description
List[int]

The lattice's prime limit

Examples:

>>> chord = JustLatticeChord.from_name(60, [0, 0, 0], 'minor triad')
>>> chord.harmonics
[10, 12, 15]

identities: List[int] property

JustLatticeChord constituent identities.

Returns:

Type Description
List[int]

The constituent identities

Examples:

>>> chord = JustLatticeChord.from_name(60, [0, 0, 0], 'minor triad')
>>> chord.identities
[5, 3, 15]

__init__(fundamental, root, nodes)

Initializes a JustLatticeChord.

Parameters:

Name Type Description Default
fundamental float

Fundamental pitch in Hertz.

required
root List[int]

Root lattice node (the chord's root tone)

required
nodes List[List[int]]

Lattice nodes of each constituent chord tone.

required

Examples:

>>> nodes = [[-1, 0, 1], [1, 0, 0], [0, 0, 1]]
>>> JustLatticeChord(fundamental=100.0, root=[1, 0, 0], nodes=nodes)
JustLatticeChord(100.0 Hz, [3/2, 7/4, 9/8, 21/16], [3-7-9-21])
Source code in /opt/hostedtoolcache/Python/3.11.3/x64/lib/python3.11/site-packages/jintonic/chords.py
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
def __init__(
    self,
    fundamental: float,
    root: List[int],
    nodes: List[List[int]],
):
    """Initializes a JustLatticeChord.

    Parameters:
        fundamental: Fundamental pitch in Hertz.
        root: Root lattice node (the chord's root tone)
        nodes: Lattice nodes of each constituent chord tone.

    Examples:
        >>> nodes = [[-1, 0, 1], [1, 0, 0], [0, 0, 1]]
        >>> JustLatticeChord(fundamental=100.0, root=[1, 0, 0], nodes=nodes)
        JustLatticeChord(100.0 Hz, [3/2, 7/4, 9/8, 21/16], [3-7-9-21])
    """
    self._fundamental: float = float(fundamental)
    self._nodes = nodes
    self._root = root
    self.lattice = JustLattice(fundamental=self._fundamental)

from_name(fundamental, root, name) classmethod

Initializes a JustLatticeChord from a conventional chord name.

Parameters:

Name Type Description Default
fundamental float

The fundamental frequency in Hertz

required
root List[int]

The root node lattice coordinates

required
name str

The chord name

required

Returns:

Type Description
JustLatticeChord

A JustLatticeChord

The list of valid names is
  • "sub-minor triad"
  • "minor triad"
  • "diminished triad"
  • "major triad"
  • "sub-minor seventh"
  • "minor seventh"
  • "half-diminished seventh"
  • "major seventh"
  • "super-major seventh"
  • "dominant seventh"
  • "added second"
  • "minor ninth"
  • "major ninth"
  • "dominant ninth"
  • "4-6-7"
  • "5-7-9"

Examples:

>>> JustLatticeChord.from_name(60, [0, 0, 0], 'minor triad')
JustLatticeChord(60.0 Hz, [1/1, 6/5, 3/2], [5-3-15])
>>> JustLatticeChord.from_name(60, [-1, 0, 0], 'major triad')
JustLatticeChord(60.0 Hz, [4/3, 5/3, 1/1], [1-5-3])
Source code in /opt/hostedtoolcache/Python/3.11.3/x64/lib/python3.11/site-packages/jintonic/chords.py
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
@classmethod
def from_name(
    cls,
    fundamental: float,
    root: List[int],
    name: str,
) -> JustLatticeChord:
    """Initializes a JustLatticeChord from a conventional chord name.

    Parameters:
        fundamental: The fundamental frequency in Hertz
        root: The root node lattice coordinates
        name: The chord name

    Returns:
        A JustLatticeChord

    The list of valid names is:
        - "sub-minor triad"
        - "minor triad"
        - "diminished triad"
        - "major triad"
        - "sub-minor seventh"
        - "minor seventh"
        - "half-diminished seventh"
        - "major seventh"
        - "super-major seventh"
        - "dominant seventh"
        - "added second"
        - "minor ninth"
        - "major ninth"
        - "dominant ninth"
        - "4-6-7"
        - "5-7-9"

    Examples:

        >>> JustLatticeChord.from_name(60, [0, 0, 0], 'minor triad')
        JustLatticeChord(60.0 Hz, [1/1, 6/5, 3/2], [5-3-15])

        >>> JustLatticeChord.from_name(60, [-1, 0, 0], 'major triad')
        JustLatticeChord(60.0 Hz, [4/3, 5/3, 1/1], [1-5-3])
    """
    nodes = {
        "sub-minor triad": [[1, 0, 0], [-1, 0, 1]],
        "minor triad": [[1, -1, 0], [1, 0, 0]],
        "diminished triad": [[1, -1, 0], [0, -1, 1]],
        "major triad": [[0, 1, 0], [1, 0, 0]],
        "sub-minor seventh": [[-1, 0, 1], [1, 0, 0], [0, 0, 1]],
        "minor seventh": [[1, -1, 0], [1, 0, 0], [2, -1, 0]],
        "half-diminished seventh": [[1, -1, 0], [0, -1, 1], [2, -1, 0]],
        "major seventh": [[0, 1, 0], [1, 0, 0], [1, 1, 0]],
        "super-major seventh": [[2, 0, -1], [1, 0, 0], [3, 0, -1]],
        "dominant seventh": [[0, 1, 0], [1, 0, 0], [1, 1, 0], [0, 0, 1]],
        "added second": [[0, 1, 0], [1, 0, 0], [2, -1, 0]],
        "minor ninth": [[1, -1, 0], [1, 0, 0], [2, -1, 0], [2, 0, 0]],
        "major ninth": [[0, 1, 0], [1, 0, 0], [1, 1, 0], [2, 0, 0]],
        "dominant ninth": [[0, 1, 0], [1, 0, 0], [0, 0, 1], [2, 0, 0]],
        "4-6-7": [[1, 0, 0], [0, 0, 1]],
        "5-7-9": [[0, -1, 1], [2, -1, 0]],
    }
    try:
        return cls(fundamental, root, nodes[name.lower()])
    except KeyError:
        return NotImplemented

pivot(axis=3)

Pivots the JustLatticeChord along the given axis.

Parameters:

Name Type Description Default
axis int

Prime limit axis (a prime number)

3

Returns:

Type Description
JustLatticeChord

A pivoted JustLatticeChord

Note

Returns a copy

Examples:

>>> chord = JustLatticeChord.from_name(60, [0, 0, 0], 'major triad')
>>> chord.pivot(3)
JustLatticeChord(60.0 Hz, [1/1, 5/4, 4/3], [3-15-1])
Source code in /opt/hostedtoolcache/Python/3.11.3/x64/lib/python3.11/site-packages/jintonic/chords.py
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
def pivot(self, axis: int = 3) -> JustLatticeChord:
    """Pivots the JustLatticeChord along the given axis.

    Parameters:
        axis: Prime limit axis (a prime number)

    Returns:
        A pivoted JustLatticeChord

    Note:
        Returns a copy

    Examples:
        >>> chord = JustLatticeChord.from_name(60, [0, 0, 0], 'major triad')
        >>> chord.pivot(3)
        JustLatticeChord(60.0 Hz, [1/1, 5/4, 4/3], [3-15-1])
    """
    if axis > self.prime_limit:
        raise ValueError(
            "Cannot pivot on an axis greater than the chord's prime limit."
        )
    chord = deepcopy(self)
    axis_ix = generate_primes(chord.prime_limit)[1:].index(axis)
    base = min(node[axis_ix] for node in chord._nodes)
    base = 0
    for i, node in enumerate(chord._nodes):
        node[axis_ix] = base - node[axis_ix]
        chord._nodes[i] = node
    return chord

transpose(node)

JustLatticeChord transposition.

Parameters:

Name Type Description Default
node List[int]

The target root node of the transposed chord.

required

Returns:

Type Description
JustLatticeChord

A transposed JustLatticeChord

Note

Returns a copy

Examples:

>>> chord = JustLatticeChord.from_name(60, [0, 0, 0], 'minor triad')
>>> node = [1, 0, 0]
>>> chord.transpose(node)
JustLatticeChord(60.0 Hz, [3/2, 9/5, 9/8], [5-3-15])
Source code in /opt/hostedtoolcache/Python/3.11.3/x64/lib/python3.11/site-packages/jintonic/chords.py
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
def transpose(self, node: List[int]) -> JustLatticeChord:
    """JustLatticeChord transposition.

    Parameters:
        node: The target root node of the transposed chord.

    Returns:
        A transposed JustLatticeChord

    Note:
        Returns a copy

    Examples:
        >>> chord = JustLatticeChord.from_name(60, [0, 0, 0], 'minor triad')
        >>> node = [1, 0, 0]
        >>> chord.transpose(node)
        JustLatticeChord(60.0 Hz, [3/2, 9/5, 9/8], [5-3-15])
    """
    chord = deepcopy(self)
    chord.root = node
    chord.lattice.to_node((node))

    return chord