Skip to content

Serial

pc_set_functions

Functions for retrieving one pitch class set property directly from another.

Most of the retrieval function names are in the form <call-on-type>_to_<return-type> e.g. prime_to_combinatoriality Some are simple mappings from one entry to another. Anything starting with pitches involves more calculation.

Broadly as implemented by Mark Gotham for Serial_Analyser after Robert Morris, but the functions are general and not really named algorithms in sense used elsewhere on this code base.

Author: Mark Gotham

Functions

set_classes_from_cardinality

set_classes_from_cardinality(cardinality: int) -> list

Find pitch class set data matching given cardinality.

Parameters:

  • cardinality (int) –

    The cardinality of the set (2–10 inclusive).

Returns:

  • list

    The pitch class set data for that cardinality.

Examples:

>>> set_classes_from_cardinality(2)[0]
('2-1', (0, 1), (1, 0, 0, 0, 0, 0), 2)
Source code in amads/pitch/pc_set_functions.py
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
def set_classes_from_cardinality(cardinality: int) -> list:
    """
    Find pitch class set data matching given cardinality.

    Parameters
    ----------
    cardinality: int
        The cardinality of the set (2–10 inclusive).

    Returns
    -------
    list
        The pitch class set data for that cardinality.

    Examples
    --------
    >>> set_classes_from_cardinality(2)[0]
    ('2-1', (0, 1), (1, 0, 0, 0, 0, 0), 2)

    """
    if not (1 < cardinality < 11):
        raise ValueError("Invalid cardinality: must be 2-10 (inclusive).")
    return pc_sets.set_classes[cardinality]

prime_to_combinatoriality

prime_to_combinatoriality(prime: tuple[int, ...]) -> int

Find the combinatoriality status for a given prime form.

Parameters:

  • prime (tuple[int, ...]) –

    A prime form expressed as a tuple of integers.

Returns:

  • int

    The number of distinct transformations (non-invariant transpositions and / or inversions).

Examples:

>>> prime_to_combinatoriality((0, 1, 2, 3))
12
Source code in amads/pitch/pc_set_functions.py
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
def prime_to_combinatoriality(prime: tuple[int, ...]) -> int:
    """
    Find the combinatoriality status for a given prime form.

    Parameters
    ----------
    prime: tuple[int, ...]
        A prime form expressed as a tuple of integers.

    Returns
    -------
    int
        The number of distinct transformations (non-invariant transpositions and / or inversions).

    Examples
    --------
    >>> prime_to_combinatoriality((0, 1, 2, 3))
    12
    """
    data = set_classes_from_cardinality(len(prime))
    for x in data:
        if x[1] == prime:
            return x[3]
    raise ValueError(f"{prime} is not a valid prime form")

interval_vector_to_combinatoriality

interval_vector_to_combinatoriality(vector: tuple[int, ...]) -> str

Find the combinatoriality status for a given interval vector.

Parameters:

  • vector (tuple[int, ...]) –

    An interval vector for any set with 2–10 distinct pitches, expressed as a tuple of 6 integers.

Returns:

  • str

    The combinatoriality status: one of T, I, RI, A, or an empty string for non-combinatorial cases.

Examples:

>>> interval_vector_to_combinatoriality((4, 3, 2, 1, 0, 0))  # 5-1
12
Source code in amads/pitch/pc_set_functions.py
 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
def interval_vector_to_combinatoriality(vector: tuple[int, ...]) -> str:
    """
    Find the combinatoriality status for a given interval vector.

    Parameters
    ----------
    vector: tuple[int, ...]
        An interval vector for any set with 2–10 distinct pitches,
        expressed as a tuple of 6 integers.

    Returns
    -------
    str
        The combinatoriality status: one of ``T``, ``I``, ``RI``, ``A``,
        or an empty string for non-combinatorial cases.

    Examples
    --------
    >>> interval_vector_to_combinatoriality((4, 3, 2, 1, 0, 0))  # 5-1
    12
    """
    if len(vector) != 6:
        raise ValueError(f"{vector} is not a valid interval vector")
    total = sum(vector)
    total_to_cardinality = {
        1: 2,
        3: 3,
        6: 4,
        10: 5,
        15: 6,
        21: 7,
        28: 8,
        36: 9,
        45: 10,
    }
    if total not in total_to_cardinality:
        raise ValueError(f"{vector} is not a valid interval vector")
    data = set_classes_from_cardinality(total_to_cardinality[total])
    for x in data:
        if x[2] == vector:
            return x[-1]
    raise ValueError(f"{vector} is not a valid interval vector")

interval_to_interval_class

interval_to_interval_class(interval: int) -> int

Map an interval (any integer, positive or negative and any size) to an interval class (integer in the range 0–6).

Parameters:

  • interval (int) –

    Any integer representing a pitch interval.

Returns:

  • int

    The interval class in the range 0–6.

Examples:

>>> interval_to_interval_class(0)
0
>>> interval_to_interval_class(-1)
1
>>> interval_to_interval_class(-2)
2
>>> interval_to_interval_class(11)
1
>>> interval_to_interval_class(7)
5
>>> interval_to_interval_class(-100)
4
Source code in amads/pitch/pc_set_functions.py
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
def interval_to_interval_class(interval: int) -> int:
    """
    Map an interval (any integer, positive or negative and any size)
    to an interval class (integer in the range 0–6).

    Parameters
    ----------
    interval: int
        Any integer representing a pitch interval.

    Returns
    -------
    int
        The interval class in the range 0–6.

    Examples
    --------
    >>> interval_to_interval_class(0)
    0

    >>> interval_to_interval_class(-1)
    1

    >>> interval_to_interval_class(-2)
    2

    >>> interval_to_interval_class(11)
    1

    >>> interval_to_interval_class(7)
    5

    >>> interval_to_interval_class(-100)
    4
    """
    reduced = abs(interval) % 12
    return reduced if reduced <= 6 else 12 - reduced

interval_vector_to_interval_class_vector

interval_vector_to_interval_class_vector(
    interval_vector: tuple[int, ...],
) -> tuple[int, ...]

Map an interval vector of range(0, 12) to an interval class vector of range(1, 7).

Parameters:

  • interval_vector (tuple[int, ...]) –

    A 12-element interval vector.

Returns:

  • tuple[int, ...]

    A 6-element interval class vector.

Examples:

>>> interval_vector_to_interval_class_vector((1, 0, 5, 7, 2, 2, 0, 3, 5, 0, 8, 4))
(4, 13, 7, 7, 5, 0)
Source code in amads/pitch/pc_set_functions.py
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
def interval_vector_to_interval_class_vector(
    interval_vector: tuple[int, ...]
) -> tuple[int, ...]:
    """
    Map an interval vector of range(0, 12) to an interval class vector of range(1, 7).

    Parameters
    ----------
    interval_vector: tuple[int, ...]
        A 12-element interval vector.

    Returns
    -------
    tuple[int, ...]
        A 6-element interval class vector.

    Examples
    --------
    >>> interval_vector_to_interval_class_vector((1, 0, 5, 7, 2, 2, 0, 3, 5, 0, 8, 4))
    (4, 13, 7, 7, 5, 0)
    """
    interval_class_vector = [0] * 6
    for i in range(1, 6):
        interval_class_vector[i - 1] = (
            interval_vector[i] + interval_vector[12 - i]
        )
    interval_class_vector[5] = interval_vector[6]  # special case
    return tuple(interval_class_vector)

pitches_to_combinatoriality

pitches_to_combinatoriality(pitches: Sequence[int]) -> str

Find the combinatoriality status for a given list of pitches.

Parameters:

  • pitches (Sequence[int]) –

    A sequence of integers (0–11) for sets with 2–10 distinct pitches.

Returns:

  • str

    The combinatoriality status as a string.

Examples:

>>> pitches_to_combinatoriality((0, 1, 2, 3, 4, 5, 6, 7, 8, 9))
12
Source code in amads/pitch/pc_set_functions.py
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
def pitches_to_combinatoriality(pitches: Sequence[int]) -> str:
    """
    Find the combinatoriality status for a given list of pitches.

    Parameters
    ----------
    pitches: Sequence[int]
        A sequence of integers (0–11) for sets with 2–10 distinct pitches.

    Returns
    -------
    str
        The combinatoriality status as a string.

    Examples
    --------
    >>> pitches_to_combinatoriality((0, 1, 2, 3, 4, 5, 6, 7, 8, 9))
    12
    """
    icv = set_to_interval_vector(pitches)
    return interval_vector_to_combinatoriality(icv)

distinct_pcs

distinct_pcs(pitches: Sequence[int]) -> list[int]

Find the distinct pitch classes for a given sequence of pitches.

Parameters:

  • pitches (Sequence[int]) –

    A sequence of pitches (any integers).

Returns:

  • list[int]

    A list of distinct pitch classes in the range 0–11.

Examples:

>>> distinct_pcs((0, 0, 1, 1, 14))
[0, 1, 2]
Source code in amads/pitch/pc_set_functions.py
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
def distinct_pcs(pitches: Sequence[int]) -> list[int]:
    """
    Find the distinct pitch classes for a given sequence of pitches.

    Parameters
    ----------
    pitches: Sequence[int]
        A sequence of pitches (any integers).

    Returns
    -------
    list[int]
        A list of distinct pitch classes in the range 0–11.

    Examples
    --------
    >>> distinct_pcs((0, 0, 1, 1, 14))
    [0, 1, 2]
    """
    return list({p % 12 for p in pitches})

set_to_interval_vector

set_to_interval_vector(user_set: Sequence[int]) -> tuple[int, ...]

Generates the interval vector for a set of pitches: the counts of each interval class present between all pairs of elements.

Parameters:

  • user_set (Sequence[int]) –

    A sequence of integers representing pitch classes. Order does not affect the result.

Returns:

  • tuple[int, ...]

    A tuple of length 6 where index i contains the count of interval class i+1 among all pairs in user_set.

Examples:

>>> set_to_interval_vector([1, 3, 4, 6])
(1, 2, 2, 0, 1, 0)
>>> set_to_interval_vector([0, 4, 7])  # C major triad
(0, 0, 1, 1, 1, 0)
Source code in amads/pitch/pc_set_functions.py
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
def set_to_interval_vector(
    user_set: Sequence[int],
) -> tuple[int, ...]:
    """
    Generates the interval vector for a set of pitches:
    the counts of each interval class present between all pairs of elements.

    Parameters
    ----------
    user_set: Sequence[int]
        A sequence of integers representing pitch classes.
        Order does not affect the result.

    Returns
    -------
    tuple[int, ...]
        A tuple of length 6 where index ``i`` contains the count of
        interval class ``i+1`` among all pairs in ``user_set``.

    Examples
    --------
    >>> set_to_interval_vector([1, 3, 4, 6])
    (1, 2, 2, 0, 1, 0)

    >>> set_to_interval_vector([0, 4, 7])  # C major triad
    (0, 0, 1, 1, 1, 0)

    """
    differences = [
        interval_to_interval_class(x) for x in pairwise_differences(user_set)
    ]
    differences = multiset_to_vector(differences, max_index=6)
    return tuple(differences[1:])

pitches_to_forte_class

pitches_to_forte_class(pitches: Sequence[int]) -> str

Find the Forte class for a given list of pitches.

Parameters:

  • pitches (Sequence[int]) –

    A sequence of integers (0–11) for sets with 2–10 distinct pitches.

Returns:

  • str

    The Forte class.

Examples:

>>> pitches_to_forte_class((0, 1, 2, 3, 4, 5, 6, 7, 8))
'9-1'
Source code in amads/pitch/pc_set_functions.py
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
def pitches_to_forte_class(pitches: Sequence[int]) -> str:
    """
    Find the Forte class for a given list of pitches.

    Parameters
    ----------
    pitches: Sequence[int]
        A sequence of integers (0–11) for sets with 2–10 distinct pitches.

    Returns
    -------
    str
        The Forte class.

    Examples
    --------
    >>> pitches_to_forte_class((0, 1, 2, 3, 4, 5, 6, 7, 8))
    '9-1'
    """
    data = set_classes_from_cardinality(len(pitches))
    prime = pitches_to_prime(pitches)
    for x in data:
        if x[1] == prime:
            return x[0]
    raise ValueError(f"{pitches} is not a valid entry.")

pitches_to_prime

pitches_to_prime(pitches: Sequence[int]) -> tuple[int, ...]

Find the prime form for a given list of pitches.

This function first converts the pitches to their interval vector. (That step is easy and fast). This vector can then unambiguously give the prime form except for Z-related pairs. This affects one pair of tetrachords (2 prime forms) and 15 pairs of hexachords (30 primes). In those cases, the prime form is worked out by comparing the pitch list against the pair of options in both inversions until a match is found.

Parameters:

  • pitches (Sequence[int]) –

    A sequence of integers (0–11) for sets with 2–10 distinct pitches.

Returns:

  • tuple[int, ...]

    The prime form.

Examples:

>>> pitches_to_prime((9, 0, 1, 2, 3, 4, 5, 6, 7, 8))
(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
Source code in amads/pitch/pc_set_functions.py
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
def pitches_to_prime(pitches: Sequence[int]) -> tuple[int, ...]:
    """
    Find the prime form for a given list of pitches.

    This function first converts the pitches to their interval vector.
    (That step is easy and fast).
    This vector can then unambiguously give the prime form except for Z-related pairs.
    This affects one pair of tetrachords (2 prime forms) and 15 pairs of hexachords (30 primes).
    In those cases, the prime form is worked out by comparing the pitch list against
    the pair of options in both inversions until a match is found.

    Parameters
    ----------
    pitches: Sequence[int]
        A sequence of integers (0–11) for sets with 2–10 distinct pitches.

    Returns
    -------
    tuple[int, ...]
        The prime form.

    Examples
    --------
    >>> pitches_to_prime((9, 0, 1, 2, 3, 4, 5, 6, 7, 8))
    (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
    """
    pitches = distinct_pcs(pitches)
    vector = set_to_interval_vector(pitches)
    data = set_classes_from_cardinality(len(pitches))

    primes = [x[1] for x in data if x[2] == vector]

    if len(primes) == 1:
        return primes[0]
    elif len(primes) > 1:
        for prime in primes:
            inverted = pitch_list_transformations.invert(prime)
            for t in [prime, inverted]:
                if transposition_equivalent(t, pitches):
                    return prime
    raise ValueError(f"{pitches} did not match any prime form.")

transposition_equivalent

transposition_equivalent(
    set1: Sequence[int], set2: Sequence[int]
) -> bool

Determine whether two pitch class sets are transposition equivalent.

Parameters:

  • set1 (Sequence[int]) –

    A pitch class set as a sequence of integers (0–11).

  • set2 (Sequence[int]) –

    A pitch class set as a sequence of integers (0–11).

Returns:

  • bool

    True if the two sets are transposition equivalent, False otherwise.

Examples:

Meaningully True:

>>> transposition_equivalent((0, 1, 2, 3, 4, 5, 6, 7, 8), (1, 2, 3, 4, 5, 6, 7, 8, 9))
True

Trivially True:

>>> transposition_equivalent((0, 1, 2, 3, 4, 5, 6, 7, 8), (0, 1, 2, 3, 4, 5, 6, 7, 8))
True

False:

>>> transposition_equivalent((0, 1, 2, 3, 4, 5, 6, 7, 8), (0, 1, 2, 3, 4, 5, 6, 7))
False
Source code in amads/pitch/pc_set_functions.py
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
def transposition_equivalent(
    set1: Sequence[int],
    set2: Sequence[int],
) -> bool:
    """
    Determine whether two pitch class sets are transposition equivalent.

    Parameters
    ----------
    set1: Sequence[int]
        A pitch class set as a sequence of integers (0–11).
    set2: Sequence[int]
        A pitch class set as a sequence of integers (0–11).

    Returns
    -------
    bool
        True if the two sets are transposition equivalent, False otherwise.

    Examples
    --------

    Meaningully True:
    >>> transposition_equivalent((0, 1, 2, 3, 4, 5, 6, 7, 8), (1, 2, 3, 4, 5, 6, 7, 8, 9))
    True

    Trivially True:
    >>> transposition_equivalent((0, 1, 2, 3, 4, 5, 6, 7, 8), (0, 1, 2, 3, 4, 5, 6, 7, 8))
    True

    False:
    >>> transposition_equivalent((0, 1, 2, 3, 4, 5, 6, 7, 8), (0, 1, 2, 3, 4, 5, 6, 7))
    False

    """
    sorted_set2 = sorted(set2)
    for i in range(12):
        if (
            sorted(pitch_list_transformations.transpose_by(set1, i))
            == sorted_set2
        ):
            return True
    return False

options: members: false


set_classes_from_cardinality

set_classes_from_cardinality(cardinality: int) -> list

Find pitch class set data matching given cardinality.

Parameters:

  • cardinality (int) –

    The cardinality of the set (2–10 inclusive).

Returns:

  • list

    The pitch class set data for that cardinality.

Examples:

>>> set_classes_from_cardinality(2)[0]
('2-1', (0, 1), (1, 0, 0, 0, 0, 0), 2)
Source code in amads/pitch/pc_set_functions.py
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
def set_classes_from_cardinality(cardinality: int) -> list:
    """
    Find pitch class set data matching given cardinality.

    Parameters
    ----------
    cardinality: int
        The cardinality of the set (2–10 inclusive).

    Returns
    -------
    list
        The pitch class set data for that cardinality.

    Examples
    --------
    >>> set_classes_from_cardinality(2)[0]
    ('2-1', (0, 1), (1, 0, 0, 0, 0, 0), 2)

    """
    if not (1 < cardinality < 11):
        raise ValueError("Invalid cardinality: must be 2-10 (inclusive).")
    return pc_sets.set_classes[cardinality]

prime_to_combinatoriality

prime_to_combinatoriality(prime: tuple[int, ...]) -> int

Find the combinatoriality status for a given prime form.

Parameters:

  • prime (tuple[int, ...]) –

    A prime form expressed as a tuple of integers.

Returns:

  • int

    The number of distinct transformations (non-invariant transpositions and / or inversions).

Examples:

>>> prime_to_combinatoriality((0, 1, 2, 3))
12
Source code in amads/pitch/pc_set_functions.py
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
def prime_to_combinatoriality(prime: tuple[int, ...]) -> int:
    """
    Find the combinatoriality status for a given prime form.

    Parameters
    ----------
    prime: tuple[int, ...]
        A prime form expressed as a tuple of integers.

    Returns
    -------
    int
        The number of distinct transformations (non-invariant transpositions and / or inversions).

    Examples
    --------
    >>> prime_to_combinatoriality((0, 1, 2, 3))
    12
    """
    data = set_classes_from_cardinality(len(prime))
    for x in data:
        if x[1] == prime:
            return x[3]
    raise ValueError(f"{prime} is not a valid prime form")

interval_vector_to_combinatoriality

interval_vector_to_combinatoriality(vector: tuple[int, ...]) -> str

Find the combinatoriality status for a given interval vector.

Parameters:

  • vector (tuple[int, ...]) –

    An interval vector for any set with 2–10 distinct pitches, expressed as a tuple of 6 integers.

Returns:

  • str

    The combinatoriality status: one of T, I, RI, A, or an empty string for non-combinatorial cases.

Examples:

>>> interval_vector_to_combinatoriality((4, 3, 2, 1, 0, 0))  # 5-1
12
Source code in amads/pitch/pc_set_functions.py
 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
def interval_vector_to_combinatoriality(vector: tuple[int, ...]) -> str:
    """
    Find the combinatoriality status for a given interval vector.

    Parameters
    ----------
    vector: tuple[int, ...]
        An interval vector for any set with 2–10 distinct pitches,
        expressed as a tuple of 6 integers.

    Returns
    -------
    str
        The combinatoriality status: one of ``T``, ``I``, ``RI``, ``A``,
        or an empty string for non-combinatorial cases.

    Examples
    --------
    >>> interval_vector_to_combinatoriality((4, 3, 2, 1, 0, 0))  # 5-1
    12
    """
    if len(vector) != 6:
        raise ValueError(f"{vector} is not a valid interval vector")
    total = sum(vector)
    total_to_cardinality = {
        1: 2,
        3: 3,
        6: 4,
        10: 5,
        15: 6,
        21: 7,
        28: 8,
        36: 9,
        45: 10,
    }
    if total not in total_to_cardinality:
        raise ValueError(f"{vector} is not a valid interval vector")
    data = set_classes_from_cardinality(total_to_cardinality[total])
    for x in data:
        if x[2] == vector:
            return x[-1]
    raise ValueError(f"{vector} is not a valid interval vector")

pitches_to_combinatoriality

pitches_to_combinatoriality(pitches: Sequence[int]) -> str

Find the combinatoriality status for a given list of pitches.

Parameters:

  • pitches (Sequence[int]) –

    A sequence of integers (0–11) for sets with 2–10 distinct pitches.

Returns:

  • str

    The combinatoriality status as a string.

Examples:

>>> pitches_to_combinatoriality((0, 1, 2, 3, 4, 5, 6, 7, 8, 9))
12
Source code in amads/pitch/pc_set_functions.py
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
def pitches_to_combinatoriality(pitches: Sequence[int]) -> str:
    """
    Find the combinatoriality status for a given list of pitches.

    Parameters
    ----------
    pitches: Sequence[int]
        A sequence of integers (0–11) for sets with 2–10 distinct pitches.

    Returns
    -------
    str
        The combinatoriality status as a string.

    Examples
    --------
    >>> pitches_to_combinatoriality((0, 1, 2, 3, 4, 5, 6, 7, 8, 9))
    12
    """
    icv = set_to_interval_vector(pitches)
    return interval_vector_to_combinatoriality(icv)

distinct_pcs

distinct_pcs(pitches: Sequence[int]) -> list[int]

Find the distinct pitch classes for a given sequence of pitches.

Parameters:

  • pitches (Sequence[int]) –

    A sequence of pitches (any integers).

Returns:

  • list[int]

    A list of distinct pitch classes in the range 0–11.

Examples:

>>> distinct_pcs((0, 0, 1, 1, 14))
[0, 1, 2]
Source code in amads/pitch/pc_set_functions.py
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
def distinct_pcs(pitches: Sequence[int]) -> list[int]:
    """
    Find the distinct pitch classes for a given sequence of pitches.

    Parameters
    ----------
    pitches: Sequence[int]
        A sequence of pitches (any integers).

    Returns
    -------
    list[int]
        A list of distinct pitch classes in the range 0–11.

    Examples
    --------
    >>> distinct_pcs((0, 0, 1, 1, 14))
    [0, 1, 2]
    """
    return list({p % 12 for p in pitches})

set_to_interval_vector

set_to_interval_vector(user_set: Sequence[int]) -> tuple[int, ...]

Generates the interval vector for a set of pitches: the counts of each interval class present between all pairs of elements.

Parameters:

  • user_set (Sequence[int]) –

    A sequence of integers representing pitch classes. Order does not affect the result.

Returns:

  • tuple[int, ...]

    A tuple of length 6 where index i contains the count of interval class i+1 among all pairs in user_set.

Examples:

>>> set_to_interval_vector([1, 3, 4, 6])
(1, 2, 2, 0, 1, 0)
>>> set_to_interval_vector([0, 4, 7])  # C major triad
(0, 0, 1, 1, 1, 0)
Source code in amads/pitch/pc_set_functions.py
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
def set_to_interval_vector(
    user_set: Sequence[int],
) -> tuple[int, ...]:
    """
    Generates the interval vector for a set of pitches:
    the counts of each interval class present between all pairs of elements.

    Parameters
    ----------
    user_set: Sequence[int]
        A sequence of integers representing pitch classes.
        Order does not affect the result.

    Returns
    -------
    tuple[int, ...]
        A tuple of length 6 where index ``i`` contains the count of
        interval class ``i+1`` among all pairs in ``user_set``.

    Examples
    --------
    >>> set_to_interval_vector([1, 3, 4, 6])
    (1, 2, 2, 0, 1, 0)

    >>> set_to_interval_vector([0, 4, 7])  # C major triad
    (0, 0, 1, 1, 1, 0)

    """
    differences = [
        interval_to_interval_class(x) for x in pairwise_differences(user_set)
    ]
    differences = multiset_to_vector(differences, max_index=6)
    return tuple(differences[1:])

pitches_to_forte_class

pitches_to_forte_class(pitches: Sequence[int]) -> str

Find the Forte class for a given list of pitches.

Parameters:

  • pitches (Sequence[int]) –

    A sequence of integers (0–11) for sets with 2–10 distinct pitches.

Returns:

  • str

    The Forte class.

Examples:

>>> pitches_to_forte_class((0, 1, 2, 3, 4, 5, 6, 7, 8))
'9-1'
Source code in amads/pitch/pc_set_functions.py
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
def pitches_to_forte_class(pitches: Sequence[int]) -> str:
    """
    Find the Forte class for a given list of pitches.

    Parameters
    ----------
    pitches: Sequence[int]
        A sequence of integers (0–11) for sets with 2–10 distinct pitches.

    Returns
    -------
    str
        The Forte class.

    Examples
    --------
    >>> pitches_to_forte_class((0, 1, 2, 3, 4, 5, 6, 7, 8))
    '9-1'
    """
    data = set_classes_from_cardinality(len(pitches))
    prime = pitches_to_prime(pitches)
    for x in data:
        if x[1] == prime:
            return x[0]
    raise ValueError(f"{pitches} is not a valid entry.")

pitches_to_prime

pitches_to_prime(pitches: Sequence[int]) -> tuple[int, ...]

Find the prime form for a given list of pitches.

This function first converts the pitches to their interval vector. (That step is easy and fast). This vector can then unambiguously give the prime form except for Z-related pairs. This affects one pair of tetrachords (2 prime forms) and 15 pairs of hexachords (30 primes). In those cases, the prime form is worked out by comparing the pitch list against the pair of options in both inversions until a match is found.

Parameters:

  • pitches (Sequence[int]) –

    A sequence of integers (0–11) for sets with 2–10 distinct pitches.

Returns:

  • tuple[int, ...]

    The prime form.

Examples:

>>> pitches_to_prime((9, 0, 1, 2, 3, 4, 5, 6, 7, 8))
(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
Source code in amads/pitch/pc_set_functions.py
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
def pitches_to_prime(pitches: Sequence[int]) -> tuple[int, ...]:
    """
    Find the prime form for a given list of pitches.

    This function first converts the pitches to their interval vector.
    (That step is easy and fast).
    This vector can then unambiguously give the prime form except for Z-related pairs.
    This affects one pair of tetrachords (2 prime forms) and 15 pairs of hexachords (30 primes).
    In those cases, the prime form is worked out by comparing the pitch list against
    the pair of options in both inversions until a match is found.

    Parameters
    ----------
    pitches: Sequence[int]
        A sequence of integers (0–11) for sets with 2–10 distinct pitches.

    Returns
    -------
    tuple[int, ...]
        The prime form.

    Examples
    --------
    >>> pitches_to_prime((9, 0, 1, 2, 3, 4, 5, 6, 7, 8))
    (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
    """
    pitches = distinct_pcs(pitches)
    vector = set_to_interval_vector(pitches)
    data = set_classes_from_cardinality(len(pitches))

    primes = [x[1] for x in data if x[2] == vector]

    if len(primes) == 1:
        return primes[0]
    elif len(primes) > 1:
        for prime in primes:
            inverted = pitch_list_transformations.invert(prime)
            for t in [prime, inverted]:
                if transposition_equivalent(t, pitches):
                    return prime
    raise ValueError(f"{pitches} did not match any prime form.")

transposition_equivalent

transposition_equivalent(
    set1: Sequence[int], set2: Sequence[int]
) -> bool

Determine whether two pitch class sets are transposition equivalent.

Parameters:

  • set1 (Sequence[int]) –

    A pitch class set as a sequence of integers (0–11).

  • set2 (Sequence[int]) –

    A pitch class set as a sequence of integers (0–11).

Returns:

  • bool

    True if the two sets are transposition equivalent, False otherwise.

Examples:

Meaningully True:

>>> transposition_equivalent((0, 1, 2, 3, 4, 5, 6, 7, 8), (1, 2, 3, 4, 5, 6, 7, 8, 9))
True

Trivially True:

>>> transposition_equivalent((0, 1, 2, 3, 4, 5, 6, 7, 8), (0, 1, 2, 3, 4, 5, 6, 7, 8))
True

False:

>>> transposition_equivalent((0, 1, 2, 3, 4, 5, 6, 7, 8), (0, 1, 2, 3, 4, 5, 6, 7))
False
Source code in amads/pitch/pc_set_functions.py
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
def transposition_equivalent(
    set1: Sequence[int],
    set2: Sequence[int],
) -> bool:
    """
    Determine whether two pitch class sets are transposition equivalent.

    Parameters
    ----------
    set1: Sequence[int]
        A pitch class set as a sequence of integers (0–11).
    set2: Sequence[int]
        A pitch class set as a sequence of integers (0–11).

    Returns
    -------
    bool
        True if the two sets are transposition equivalent, False otherwise.

    Examples
    --------

    Meaningully True:
    >>> transposition_equivalent((0, 1, 2, 3, 4, 5, 6, 7, 8), (1, 2, 3, 4, 5, 6, 7, 8, 9))
    True

    Trivially True:
    >>> transposition_equivalent((0, 1, 2, 3, 4, 5, 6, 7, 8), (0, 1, 2, 3, 4, 5, 6, 7, 8))
    True

    False:
    >>> transposition_equivalent((0, 1, 2, 3, 4, 5, 6, 7, 8), (0, 1, 2, 3, 4, 5, 6, 7))
    False

    """
    sorted_set2 = sorted(set2)
    for i in range(12):
        if (
            sorted(pitch_list_transformations.transpose_by(set1, i))
            == sorted_set2
        ):
            return True
    return False

pc_sets

Look-up tables for the properties of pitch class sets. Note: this toolkit also provides algorithmic functions for retrieving one property directly from another.

Each pitch class set entry features the following properties:

  • Forte index;
  • prime form (according to Forte's system);
  • interval vector;
  • number of distinct transformations (non-invariant transpositions and / or inversions).

For the hexachords (only), an additional entry provides the combinatoriality status from among 5 options:

  • 'A' for all-combinatorial (6 hexachords total),
  • 'T' for transposition only (only 1),
  • 'I' for inversion only (13),
  • 'RI' for retrograde-inversion only (13), and
  • '' (an empty string) for non-combinatorial (16).

For more information on set classes and a more detailed list of properties, see Robert Morris's table and brief explanation (with further sources) here: http://ecmc.rochester.edu/rdm/pdflib/set-class.table.pdf

Source: Gotham and Yust, Serial Analyser, DLfM 2021 https://github.com/MarkGotham/Serial_Analyser

Author: Mark Gotham, 2021

Module-level Variable

pc_sets - Tuple with (Forte index, prime form, interval vector, number of transformations, [combinatoriality status for hexachords only])


serial

The pitch_list_transformations module provides basic functions for transforming pitch lists (e.g., transposition, inversion, retrograde, rotation).

This small module provides some more niche routines that are specific to tone rows in serial music.

Functions

rotate_hexachords

rotate_hexachords(
    row: Union[List, Tuple], transpose_iterations: bool = False
) -> list

Implements a set of hexachord rotations of the kind described in krenek 1960, p.212. Splits the row into two hexachords and iteratively rotates each. This function returns a list of lists with each iteration until the cycle is complete and come full circle.

Parameters:

  • row (Union[List, Tuple]) –

    A tone row, or any sequence of 12 integers.

  • transpose_iterations (bool, default: False ) –

    If True, transpose each iteration to start on the original pitch of the hexachord. This alternative is also described by krenek. Note this often converts a 12-tone row into one with repeated pitches.

Returns:

  • list

    A list of lists with the full cycle.

Examples:

>>> row_krenek = [5, 7, 9, 10, 1, 3, 11, 0, 2, 4, 6, 8]
>>> for x in rotate_hexachords(row_krenek):
...     print(x)
[5, 7, 9, 10, 1, 3, 11, 0, 2, 4, 6, 8]
[7, 9, 10, 1, 3, 5, 0, 2, 4, 6, 8, 11]
[9, 10, 1, 3, 5, 7, 2, 4, 6, 8, 11, 0]
[10, 1, 3, 5, 7, 9, 4, 6, 8, 11, 0, 2]
[1, 3, 5, 7, 9, 10, 6, 8, 11, 0, 2, 4]
[3, 5, 7, 9, 10, 1, 8, 11, 0, 2, 4, 6]
[5, 7, 9, 10, 1, 3, 11, 0, 2, 4, 6, 8]
Source code in amads/pitch/serial.py
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
def rotate_hexachords(
    row: Union[List, Tuple], transpose_iterations: bool = False
) -> list:
    """
    Implements a set of hexachord rotations of the kind described in krenek 1960, p.212.
    Splits the row into two hexachords and iteratively rotates each.
    This function returns a list of lists with each iteration until
    the cycle is complete and come full circle.


    Parameters
    ----------
    row
        A tone row, or any sequence of 12 integers.
    transpose_iterations
        If True, transpose each iteration to start on the original pitch of the hexachord.
        This alternative is also described by krenek.
        Note this often converts a 12-tone row into one with repeated pitches.

    Returns
    -------
    list
        A list of lists with the full cycle.

    Examples
    --------
    >>> row_krenek = [5, 7, 9, 10, 1, 3, 11, 0, 2, 4, 6, 8]
    >>> for x in rotate_hexachords(row_krenek):
    ...     print(x)
    [5, 7, 9, 10, 1, 3, 11, 0, 2, 4, 6, 8]
    [7, 9, 10, 1, 3, 5, 0, 2, 4, 6, 8, 11]
    [9, 10, 1, 3, 5, 7, 2, 4, 6, 8, 11, 0]
    [10, 1, 3, 5, 7, 9, 4, 6, 8, 11, 0, 2]
    [1, 3, 5, 7, 9, 10, 6, 8, 11, 0, 2, 4]
    [3, 5, 7, 9, 10, 1, 8, 11, 0, 2, 4, 6]
    [5, 7, 9, 10, 1, 3, 11, 0, 2, 4, 6, 8]
    """

    assert len(row) == 12

    rows = [row]  # initialise with starting

    hexachord1note1 = row[0]
    hexachord2note1 = row[6]

    for i in range(1, 6):
        first_hexachord = row[i:6] + row[0:i]
        second_hexachord = row[6 + i :] + row[6 : 6 + i]

        if transpose_iterations:
            first_hexachord = transpose_to(
                first_hexachord, start=hexachord1note1
            )
            second_hexachord = transpose_to(
                second_hexachord, start=hexachord2note1
            )

        new_row = first_hexachord + second_hexachord
        rows.append(new_row)

    rows.append(row)  # completes the cycle

    return rows

pair_swap_krenek

pair_swap_krenek(row: Union[List, Tuple]) -> list

Iteratively swaps pairs of adjacent notes in a row with a two-step process as described in Krenek 1960, p.213.

Returns a list of 13 rows of which the last is the retrograde of the first. As such, calling this twice brings you back to the original row.

Parameters:

  • row (Union[List, Tuple]) –

    A tone row, or any sequence of 12 integers.

Returns:

  • list

    A list of lists with the full cycle.

Examples:

>>> pair_swap_row = [9, 2, 3, 6, 5, 1, 7, 4, 8, 0, 10, 11]
>>> for x in pair_swap_krenek(pair_swap_row):
...     print(x)
[9, 2, 3, 6, 5, 1, 7, 4, 8, 0, 10, 11]
[9, 3, 2, 5, 6, 7, 1, 8, 4, 10, 0, 11]
[3, 9, 5, 2, 7, 6, 8, 1, 10, 4, 11, 0]
[3, 5, 9, 7, 2, 8, 6, 10, 1, 11, 4, 0]
[5, 3, 7, 9, 8, 2, 10, 6, 11, 1, 0, 4]
[5, 7, 3, 8, 9, 10, 2, 11, 6, 0, 1, 4]
[7, 5, 8, 3, 10, 9, 11, 2, 0, 6, 4, 1]
[7, 8, 5, 10, 3, 11, 9, 0, 2, 4, 6, 1]
[8, 7, 10, 5, 11, 3, 0, 9, 4, 2, 1, 6]
[8, 10, 7, 11, 5, 0, 3, 4, 9, 1, 2, 6]
[10, 8, 11, 7, 0, 5, 4, 3, 1, 9, 6, 2]
[10, 11, 8, 0, 7, 4, 5, 1, 3, 6, 9, 2]
[11, 10, 0, 8, 4, 7, 1, 5, 6, 3, 2, 9]
Source code in amads/pitch/serial.py
 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
def pair_swap_krenek(row: Union[List, Tuple]) -> list:
    """
    Iteratively swaps pairs of adjacent notes in a row
    with a two-step process as described in Krenek 1960, p.213.

    Returns a list of 13 rows of which the last is the retrograde of the first.
    As such, calling this twice brings you back to the original row.

    Parameters
    ----------
    row
        A tone row, or any sequence of 12 integers.

    Returns
    -------
    list
        A list of lists with the full cycle.

    Examples
    --------
    >>> pair_swap_row = [9, 2, 3, 6, 5, 1, 7, 4, 8, 0, 10, 11]
    >>> for x in pair_swap_krenek(pair_swap_row):
    ...     print(x)
    [9, 2, 3, 6, 5, 1, 7, 4, 8, 0, 10, 11]
    [9, 3, 2, 5, 6, 7, 1, 8, 4, 10, 0, 11]
    [3, 9, 5, 2, 7, 6, 8, 1, 10, 4, 11, 0]
    [3, 5, 9, 7, 2, 8, 6, 10, 1, 11, 4, 0]
    [5, 3, 7, 9, 8, 2, 10, 6, 11, 1, 0, 4]
    [5, 7, 3, 8, 9, 10, 2, 11, 6, 0, 1, 4]
    [7, 5, 8, 3, 10, 9, 11, 2, 0, 6, 4, 1]
    [7, 8, 5, 10, 3, 11, 9, 0, 2, 4, 6, 1]
    [8, 7, 10, 5, 11, 3, 0, 9, 4, 2, 1, 6]
    [8, 10, 7, 11, 5, 0, 3, 4, 9, 1, 2, 6]
    [10, 8, 11, 7, 0, 5, 4, 3, 1, 9, 6, 2]
    [10, 11, 8, 0, 7, 4, 5, 1, 3, 6, 9, 2]
    [11, 10, 0, 8, 4, 7, 1, 5, 6, 3, 2, 9]

    """

    rows = [row]

    for pair in range(6):

        # First swap operation: starting at position 1 (2nd pitch)
        row = [x for x in row]
        for x in range(1, 11, 2):
            row[x], row[x + 1] = row[x + 1], row[x]
        rows.append(row)

        # Second swap operation: starting at position 0 (1st pitch)
        row = [x for x in row]
        for x in range(0, 12, 2):
            row[x], row[x + 1] = row[x + 1], row[x]
        rows.append(row)

    return rows

lumsdaine_cycle

lumsdaine_cycle(row: Union[list, None] = None) -> list[list]

A multipart rotation and re-combination method as reported in Hopper's "The Music of David Lumsdaine", p.21.

Parameters:

  • row (Union[list, None], default: None ) –

    A tone row, or any sequence of 12 integers.

Returns:

  • list

    A list of lists with the full cycle.

Examples:

>>> for x in lumsdaine_cycle():
...     print(x)
[11, 6, 5, 0, 3, 2, 9, 8, 10, 4, 1, 7]
[11, 9, 6, 8, 5, 10, 0, 4, 3, 1, 2, 7]
[11, 10, 2, 8, 3, 9, 0, 7, 5, 1, 6, 4]
[11, 0, 10, 7, 2, 5, 8, 1, 3, 6, 9, 4]
[2, 6, 10, 1, 11, 5, 9, 7, 3, 0, 8, 4]
[2, 9, 6, 7, 10, 3, 1, 0, 11, 8, 5, 4]
[2, 3, 5, 7, 11, 9, 1, 4, 10, 8, 6, 0]
[2, 1, 3, 4, 5, 10, 7, 8, 11, 6, 9, 0]
[5, 6, 3, 8, 2, 10, 9, 4, 11, 1, 7, 0]
[5, 9, 6, 4, 3, 11, 8, 1, 2, 7, 10, 0]
[5, 11, 10, 4, 2, 9, 8, 0, 3, 7, 6, 1]
[5, 8, 11, 0, 10, 3, 4, 7, 2, 6, 9, 1]
[10, 6, 11, 7, 5, 3, 9, 0, 2, 8, 4, 1]
[10, 9, 6, 0, 11, 2, 7, 8, 5, 4, 3, 1]
[10, 2, 3, 0, 5, 9, 7, 1, 11, 4, 6, 8]
[10, 7, 2, 1, 3, 11, 0, 4, 5, 6, 9, 8]
[3, 6, 2, 4, 10, 11, 9, 1, 5, 7, 0, 8]
[3, 9, 6, 1, 2, 5, 4, 7, 10, 0, 11, 8]
[3, 5, 11, 1, 10, 9, 4, 8, 2, 0, 6, 7]
[3, 4, 5, 8, 11, 2, 1, 0, 10, 6, 9, 7]
Source code in amads/pitch/serial.py
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
def lumsdaine_cycle(
    row: Union[list, None] = None,
) -> list[list]:
    """
    A multipart
    rotation and re-combination
    method as reported in
    Hopper's "The Music of David Lumsdaine", p.21.

    Parameters
    ----------
    row
        A tone row, or any sequence of 12 integers.

    Returns
    -------
    list
        A list of lists with the full cycle.

    Examples
    --------
    >>> for x in lumsdaine_cycle():
    ...     print(x)
    [11, 6, 5, 0, 3, 2, 9, 8, 10, 4, 1, 7]
    [11, 9, 6, 8, 5, 10, 0, 4, 3, 1, 2, 7]
    [11, 10, 2, 8, 3, 9, 0, 7, 5, 1, 6, 4]
    [11, 0, 10, 7, 2, 5, 8, 1, 3, 6, 9, 4]
    [2, 6, 10, 1, 11, 5, 9, 7, 3, 0, 8, 4]
    [2, 9, 6, 7, 10, 3, 1, 0, 11, 8, 5, 4]
    [2, 3, 5, 7, 11, 9, 1, 4, 10, 8, 6, 0]
    [2, 1, 3, 4, 5, 10, 7, 8, 11, 6, 9, 0]
    [5, 6, 3, 8, 2, 10, 9, 4, 11, 1, 7, 0]
    [5, 9, 6, 4, 3, 11, 8, 1, 2, 7, 10, 0]
    [5, 11, 10, 4, 2, 9, 8, 0, 3, 7, 6, 1]
    [5, 8, 11, 0, 10, 3, 4, 7, 2, 6, 9, 1]
    [10, 6, 11, 7, 5, 3, 9, 0, 2, 8, 4, 1]
    [10, 9, 6, 0, 11, 2, 7, 8, 5, 4, 3, 1]
    [10, 2, 3, 0, 5, 9, 7, 1, 11, 4, 6, 8]
    [10, 7, 2, 1, 3, 11, 0, 4, 5, 6, 9, 8]
    [3, 6, 2, 4, 10, 11, 9, 1, 5, 7, 0, 8]
    [3, 9, 6, 1, 2, 5, 4, 7, 10, 0, 11, 8]
    [3, 5, 11, 1, 10, 9, 4, 8, 2, 0, 6, 7]
    [3, 4, 5, 8, 11, 2, 1, 0, 10, 6, 9, 7]

    """
    if row is None:
        row = [11, 6, 5, 0, 3, 2, 9, 8, 10, 4, 1, 7]
    out = []
    for i in range(5):  # run 4, update to new starting row, and run again
        out += lumsdaine_4(row)
        row = every_nth(out[-1], start_index=4)
    return out

lumsdaine_4

lumsdaine_4(row: Union[List, None] = None) -> list[list]

One phase of lumsdaine_cycle() producing a set of 4 rows.

Parameters:

  • row (Union[List, None], default: None ) –

    A tone row, or any sequence of 12 integers.

Returns:

  • list

    A list of lists with the full cycle.

Examples:

>>> for x in lumsdaine_4([11, 6, 5, 0, 3, 2, 9, 8, 10, 4, 1, 7]):
...     print(x)
[11, 6, 5, 0, 3, 2, 9, 8, 10, 4, 1, 7]
[11, 9, 6, 8, 5, 10, 0, 4, 3, 1, 2, 7]
[11, 10, 2, 8, 3, 9, 0, 7, 5, 1, 6, 4]
[11, 0, 10, 7, 2, 5, 8, 1, 3, 6, 9, 4]
>>> for x in lumsdaine_4([5, 9, 7, 3, 0, 8, 4, 2, 6, 10, 1, 11]):
...     print(x)
[5, 9, 7, 3, 0, 8, 4, 2, 6, 10, 1, 11]
[5, 4, 9, 2, 7, 6, 3, 10, 0, 1, 8, 11]
[5, 6, 8, 2, 0, 4, 3, 11, 7, 1, 9, 10]
[5, 3, 6, 11, 8, 7, 2, 1, 0, 9, 4, 10]
Source code in amads/pitch/serial.py
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
def lumsdaine_4(
    row: Union[List, None] = None,
) -> list[list]:
    """
    One phase of `lumsdaine_cycle()`
    producing a set of 4 rows.

    Parameters
    ----------
    row
        A tone row, or any sequence of 12 integers.

    Returns
    -------
    list
        A list of lists with the full cycle.

    Examples
    --------
    >>> for x in lumsdaine_4([11, 6, 5, 0, 3, 2, 9, 8, 10, 4, 1, 7]):
    ...     print(x)
    [11, 6, 5, 0, 3, 2, 9, 8, 10, 4, 1, 7]
    [11, 9, 6, 8, 5, 10, 0, 4, 3, 1, 2, 7]
    [11, 10, 2, 8, 3, 9, 0, 7, 5, 1, 6, 4]
    [11, 0, 10, 7, 2, 5, 8, 1, 3, 6, 9, 4]

    >>> for x in lumsdaine_4([5, 9, 7, 3, 0, 8, 4, 2, 6, 10, 1, 11]):
    ...     print(x)
    [5, 9, 7, 3, 0, 8, 4, 2, 6, 10, 1, 11]
    [5, 4, 9, 2, 7, 6, 3, 10, 0, 1, 8, 11]
    [5, 6, 8, 2, 0, 4, 3, 11, 7, 1, 9, 10]
    [5, 3, 6, 11, 8, 7, 2, 1, 0, 9, 4, 10]

    """
    if row is None:
        row = [11, 6, 5, 0, 3, 2, 9, 8, 10, 4, 1, 7]
    row2 = lumsdaine_hexachord_pairs(row)
    row3 = every_nth(row2)
    row4 = lumsdaine_hexachord_pairs(row3)
    return [row, row2, row3, row4]

lumsdaine_hexachord_pairs

lumsdaine_hexachord_pairs(row: list)

Constituent step in the Lumsdaine method that re-arrange row elements indices into the order 0, 6, 1, 7 ...

Parameters:

  • row (list) –

    A tone row, or any sequence of 12 integers.

Returns:

  • list

    A list of lists with the full cycle.

Examples:

>>> lumsdaine_hexachord_pairs([11, 6, 5, 0, 3, 2, 9, 8, 10, 4, 1, 7])
[11, 9, 6, 8, 5, 10, 0, 4, 3, 1, 2, 7]
Source code in amads/pitch/serial.py
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
def lumsdaine_hexachord_pairs(row: list):
    """
    Constituent step in the Lumsdaine method
    that re-arrange row elements indices into the order 0, 6, 1, 7 ...

    Parameters
    ----------
    row
        A tone row, or any sequence of 12 integers.

    Returns
    -------
    list
        A list of lists with the full cycle.

    Examples
    --------
    >>> lumsdaine_hexachord_pairs([11, 6, 5, 0, 3, 2, 9, 8, 10, 4, 1, 7])
    [11, 9, 6, 8, 5, 10, 0, 4, 3, 1, 2, 7]
    """
    out_row = []
    for i in range(6):
        out_row += [row[i], row[i + 6]]
    return out_row

transformations

Basic functionality for transforming pitch lists expressed as integers (MIDI numbers or pitch classes) through transposition, inversion, retrograde, rotation, and more.

Most apply equally to any pitch class sequence and can therefore be use in melody and harmony settings.

Functions

transpose_by

transpose_by(
    pitches: Iterable, semitones: int, mod_12: bool = True
) -> list

Transposes a list of pitches by an interval of size set by the value of semitones.

Parameters:

  • pitches (Iterable) –

    Any list or tuple of integers representing pitches as MIDI numbers or pitch classes.

  • semitones (int) –

    How far to transpose, expressed in semitones (1 per MIDI note).

  • mod_12 (bool, default: True ) –

    If True, return values modulo 12 (necessary for pitch class sets, not for MIDI numbers)

Returns:

  • list

    A new list of the same length as the input.

Examples:

>>> transpose_by([0, 1, 2, 3,], 16, mod_12=True)
[4, 5, 6, 7]
>>> transpose_by([0, 1, 2, 3,], 16, mod_12=False)
[16, 17, 18, 19]
Source code in amads/pitch/transformations.py
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
def transpose_by(
    pitches: Iterable, semitones: int, mod_12: bool = True
) -> list:
    """
    Transposes a list of pitches by an interval of size
    set by the value of `semitones`.

    Parameters
    ----------
    pitches
        Any list or tuple of integers representing pitches as MIDI numbers or pitch classes.
    semitones
        How far to transpose, expressed in semitones (1 per MIDI note).
    mod_12
        If True, return values modulo 12 (necessary for pitch class sets, not for MIDI numbers)

    Returns
    -------
    list
        A new list of the same length as the input.

    Examples
    --------

    >>> transpose_by([0, 1, 2, 3,], 16, mod_12=True)
    [4, 5, 6, 7]

    >>> transpose_by([0, 1, 2, 3,], 16, mod_12=False)
    [16, 17, 18, 19]

    """
    result = []
    for pitch in pitches:
        transposed = pitch + semitones
        if mod_12:
            transposed %= 12
        result.append(transposed)
    return result

transpose_to

transpose_to(
    pitches: Iterable, start: int = 0, mod_12: bool = True
) -> list

Transpose a list of pitch classes to start on 0 (by default), or any another number set by the value of start.

Parameters:

  • pitches (Iterable) –

    Any list or tuple of integers representing pitches as MIDI numbers or pitch classes.

  • start (int, default: 0 ) –

    The first number of the new list.

  • mod_12 (bool, default: True ) –

    If True, return values modulo 12 (necessary for pitch class sets, not for MIDI numbers)

Returns:

  • list

    A new list of the same length as the input.

Examples:

>>> transpose_to([0, 1, 2, 3,], 16, mod_12=True)
[4, 5, 6, 7]
>>> transpose_to([0, 1, 2, 3,], 16, mod_12=False)
[16, 17, 18, 19]
Source code in amads/pitch/transformations.py
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
def transpose_to(
    pitches: Iterable, start: int = 0, mod_12: bool = True
) -> list:
    """
    Transpose a list of pitch classes to start on 0 (by default), or
    any another number set by the value of `start`.

    Parameters
    ----------
    pitches
        Any list or tuple of integers representing pitches as MIDI numbers or pitch classes.
    start
        The first number of the new list.
    mod_12
        If True, return values modulo 12 (necessary for pitch class sets, not for MIDI numbers)

    Returns
    -------
    list
        A new list of the same length as the input.

    Examples
    --------

    >>> transpose_to([0, 1, 2, 3,], 16, mod_12=True)
    [4, 5, 6, 7]

    >>> transpose_to([0, 1, 2, 3,], 16, mod_12=False)
    [16, 17, 18, 19]

    """
    difference = start - pitches[0]
    result = []
    for pitch in pitches:
        transposed = pitch + difference
        if mod_12:
            transposed %= 12
        result.append(transposed)
    return result

invert

invert(
    pitches: Iterable, use_first_not_0: bool = True, mod_12: bool = True
) -> list

Invert a list of pitch classes around a specified pitch: the starting pitch or 0.

Parameters:

  • pitches (Iterable) –

    Any list or tuple of integers representing pitches as MIDI numbers or pitch classes.

  • use_first_not_0 (bool, default: True ) –

    If true, use the first number of the list as the centre of the inversion.

  • mod_12 (bool, default: True ) –

    If True, return values modulo 12 (necessary for pitch class sets, not for MIDI numbers)

Returns:

  • list

    A new list of the same length as the input.

Examples:

>>> invert([5, 6, 7])
[5, 4, 3]
>>> invert([5, 6, 7], use_first_not_0=False)
[7, 6, 5]
Source code in amads/pitch/transformations.py
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
def invert(
    pitches: Iterable, use_first_not_0: bool = True, mod_12: bool = True
) -> list:
    """
    Invert a list of pitch classes around a specified pitch: the starting pitch or 0.

    Parameters
    ----------
    pitches
        Any list or tuple of integers representing pitches as MIDI numbers or pitch classes.
    use_first_not_0
        If true, use the first number of the list as the centre of the inversion.
    mod_12
        If True, return values modulo 12 (necessary for pitch class sets, not for MIDI numbers)

    Returns
    -------
    list
        A new list of the same length as the input.

    Examples
    --------
    >>> invert([5, 6, 7])
    [5, 4, 3]

    >>> invert([5, 6, 7], use_first_not_0=False)
    [7, 6, 5]

    """
    origin = pitches[0] if use_first_not_0 else 0
    result = []
    for pitch in pitches:
        inverted = 2 * origin - pitch
        if mod_12:
            inverted %= 12
        result.append(inverted)

    return result

pitches_to_intervals

pitches_to_intervals(
    pitches: Iterable, wrap: bool = False, mod_12: bool = True
) -> list

Get the interval succession of a list of pitches.

Parameters:

  • pitches (Iterable) –

    Any list or tuple of integers representing pitches as MIDI numbers or pitch classes.

  • wrap (bool, default: False ) –

    If true, include the interval from the last element to the first in addition.

  • mod_12 (bool, default: True ) –

    If True, return values modulo 12 (necessary for pitch class sets, not for MIDI numbers)

Returns:

  • list

    A new list of the same length as the input (if wrap), otherwise, one less.

Examples:

>>> pitches_to_intervals([0, 2, 5])
[2, 3]
>>> pitches_to_intervals([0, 2, 5], wrap=True)
[2, 3, 7]
Source code in amads/pitch/transformations.py
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
def pitches_to_intervals(
    pitches: Iterable, wrap: bool = False, mod_12: bool = True
) -> list:
    """
    Get the interval succession of a list of pitches.

    Parameters
    ----------
    pitches
        Any list or tuple of integers representing pitches as MIDI numbers or pitch classes.
    wrap
        If true, include the interval from the last element to the first in addition.
    mod_12
        If True, return values modulo 12 (necessary for pitch class sets, not for MIDI numbers)

    Returns
    -------
    list
        A new list of the same length as the input (if wrap), otherwise, one less.

    Examples
    --------
    >>> pitches_to_intervals([0, 2, 5])
    [2, 3]

    >>> pitches_to_intervals([0, 2, 5], wrap=True)
    [2, 3, 7]

    """
    intervals = []
    if wrap:
        pitches += [pitches[0]]
    for i in range(1, len(pitches)):
        i = pitches[i] - pitches[i - 1]
        if mod_12:
            i %= 12
        intervals.append(i)

    return intervals