3
3
from collections .abc import Iterable
4
4
import matplotlib .pyplot as plt
5
5
import pretty_midi as pm
6
- from utils import find_ngrams
6
+ from . utils import find_ngrams
7
7
from collections import Counter
8
8
9
9
rng = np .random .default_rng ()
@@ -37,7 +37,9 @@ def __sub__(self, other):
37
37
if isinstance (other , PitchClassInterval ):
38
38
return PitchClass ((self .p - other .i ) % self .c )
39
39
else :
40
- raise TypeError (f"Can't subtract type { type (other )} from pitch class { self .p } ." )
40
+ raise TypeError (
41
+ f"Can't subtract type { type (other )} from pitch class { self .p } ."
42
+ )
41
43
42
44
def __eq__ (self , other ):
43
45
return self .p == other .p
@@ -70,7 +72,9 @@ def __sub__(self, other):
70
72
if isinstance (other , PitchClassInterval ):
71
73
return self .i - other .i % self .c
72
74
else :
73
- raise TypeError (f"Can't subtract type { type (other )} from interval { self .i } ." )
75
+ raise TypeError (
76
+ f"Can't subtract type { type (other )} from interval { self .i } ."
77
+ )
74
78
75
79
def __eq__ (self , other ):
76
80
return self .i == other .i
@@ -89,11 +93,13 @@ def __init__(self, pcset, c: int = 12):
89
93
assert all (
90
94
x in [str (i ) for i in range (10 )] + ["T" ] + ["E" ] for x in list (pcset )
91
95
), "Some pitch classes are not valid."
92
- self .pcs = np .array ([10 if p == "T" else 11 if p == "E" else int (p ) for p in list (pcset )])
96
+ self .pcs = np .array (
97
+ [10 if p == "T" else 11 if p == "E" else int (p ) for p in list (pcset )]
98
+ )
93
99
elif isinstance (pcset , (Iterable , PitchClassSet )):
94
100
self .pcs = np .array ([int (p ) for p in pcset ])
95
101
else :
96
- raise TypeError (f"I don't recognize the pitch-class input { type (pcset )} ." )
102
+ raise TypeError (f"I don't recognize the pitch-class input { type (pcset )} ." )
97
103
98
104
def __repr__ (self ):
99
105
return f"PitchClassSet({ self .pcs } )"
@@ -138,7 +144,9 @@ def normal_form(self):
138
144
elif len (self .pcs ) == 1 :
139
145
return self
140
146
else :
141
- rotations = np .array ([np .roll (self .pcs , i ) for i in range (self .pcs .shape [0 ])])
147
+ rotations = np .array (
148
+ [np .roll (self .pcs , i ) for i in range (self .pcs .shape [0 ])]
149
+ )
142
150
for length in range (self .d - 1 , 0 , - 1 ):
143
151
spans = [(r [- 1 ] - r [0 ]) % self .c for r in rotations [:, : length + 1 ]]
144
152
mask = spans == min (spans )
@@ -214,12 +222,15 @@ def interval_vector(self):
214
222
215
223
def maximally_even (self ):
216
224
"""
217
- Calculates all maximally even sets for chromatic cardinality c
225
+ Calculates all maximally even sets for chromatic cardinality c
218
226
and diatonic cardinality d.
219
227
"""
220
228
221
- D = [ [ np .floor ((self .c * k + m ) / self .d ).astype (int ) for k in range (self .d ) ] for m in range (self .c ) ]
222
- D = [ np .array (s ) for s in set (tuple (i ) for i in D ) ]
229
+ D = [
230
+ [np .floor ((self .c * k + m ) / self .d ).astype (int ) for k in range (self .d )]
231
+ for m in range (self .c )
232
+ ]
233
+ D = [np .array (s ) for s in set (tuple (i ) for i in D )]
223
234
224
235
for s in D :
225
236
if set (s ) == set (self .pcs ):
@@ -233,29 +244,36 @@ def spectrum(self, i):
233
244
given chromatic cardinality c and diatonic cardinality d.
234
245
"""
235
246
236
- assert i in range (self .d ), f"Generic interval i={ i } has to be between 0 and { self .d - 1 } ."
247
+ assert i in range (
248
+ self .d
249
+ ), f"Generic interval i={ i } has to be between 0 and { self .d - 1 } ."
237
250
238
- return { (k - j ) % self .c for j , k in zip (self .pcs , np .roll (self .pcs , - i )) }
251
+ return {(k - j ) % self .c for j , k in zip (self .pcs , np .roll (self .pcs , - i ))}
239
252
240
253
def myhill (self ):
241
254
"""
242
255
Returns whether pitch-class set has Myhill's property.
243
256
"""
244
257
245
- specs = set ([ len (self .spectrum (i = i )) for i in range (1 ,self .d ) ])
246
-
258
+ specs = set ([len (self .spectrum (i = i )) for i in range (1 , self .d )])
259
+
247
260
return True if specs == {2 } else False
248
261
249
262
def cardinality_equals_variety (self ):
250
263
"""
251
264
Tests if cardinality equals variety holds for PCSet.
252
265
See: https://en.wikipedia.org/wiki/Cardinality_equals_variety
253
266
"""
254
- cev = True
255
- for n in range (2 ,self .d + 1 ):
256
- s = np .append (self .pcs , self .pcs [:n - 1 ])
267
+
268
+ for n in range (2 , self .d + 1 ):
269
+ s = np .append (self .pcs , self .pcs [: n - 1 ])
257
270
ngrams = find_ngrams (s , n = n )
258
- intervals = [ "" .join ([str ((gram [i ] - gram [i - 1 ]) % 12 ) for i in range (1 , len (gram ))]) for gram in ngrams ]
271
+ intervals = [
272
+ "" .join (
273
+ [str ((gram [i ] - gram [i - 1 ]) % 12 ) for i in range (1 , len (gram ))]
274
+ )
275
+ for gram in ngrams
276
+ ]
259
277
if n != len (Counter (intervals )):
260
278
return False
261
279
return True
@@ -314,7 +332,9 @@ def plot(self, kind: str = "area", save: bool = False):
314
332
ax .plot (thetas , radii , c = "k" , zorder = 5 )
315
333
ax .fill (thetas , radii , alpha = 0.75 , zorder = 4 )
316
334
else :
317
- print ("I don't recognize the plot kind." "Valid values are 'polar' and 'bar'." )
335
+ print (
336
+ "I don't recognize the plot kind." "Valid values are 'polar' and 'bar'."
337
+ )
318
338
if save :
319
339
plt .savefig (save )
320
340
@@ -332,7 +352,9 @@ def play(
332
352
starts = np .arange (n_notes ) * note_duration # onsets
333
353
ends = starts + note_duration # offsets
334
354
335
- pitches = [x for x in rng .choice (np .nonzero (self .to_vector ())[0 ], size = n_notes )]
355
+ pitches = [
356
+ x for x in rng .choice (np .nonzero (self .to_vector ())[0 ], size = n_notes )
357
+ ]
336
358
octaves = rng .choice (np .arange (3 , 7 ), size = n_notes )
337
359
midi_pitches = [(p + 12 * o ) for p , o in list (zip (pitches , octaves ))]
338
360
elif mode == "chord" :
@@ -389,11 +411,14 @@ def info(self):
389
411
s += f"interval vector\t : { self .interval_vector ()} " + "\n \n "
390
412
391
413
s += "Diatonic Scale Theory" + "\n "
392
- s += "=====================" + "\n "
393
- s += f"Maximally even: { str (self .maximally_even ())} " + "\n "
414
+ s += "=====================" + "\n "
415
+ s += f"Maximally even: { str (self .maximally_even ())} " + "\n "
394
416
s += f"Spectrum (step): { str (self .spectrum (i = 1 ))} " + "\n "
395
417
s += f"Myhill's property: { str (self .myhill ())} " + "\n "
396
- s += f"Cardinality equals variety: { str (self .cardinality_equals_variety ())} " + "\n \n "
418
+ s += (
419
+ f"Cardinality equals variety: { str (self .cardinality_equals_variety ())} "
420
+ + "\n \n "
421
+ )
397
422
398
423
s += "Serialism" + "\n "
399
424
s += "=========" + "\n "
@@ -435,7 +460,7 @@ def info(self):
435
460
436
461
# pcset.play(save_as="test.mid", mode="cloud")
437
462
438
- ## maximally even test
463
+ # maximally even test
439
464
# t = PitchClassSet("1234")
440
465
# dia = PitchClassSet("024579E")
441
466
p = PitchClassSet ("1368T" )
0 commit comments