|
2 | 2 | from itertools import combinations
|
3 | 3 | from collections.abc import Iterable
|
4 | 4 | import matplotlib.pyplot as plt
|
| 5 | +import pretty_midi as pm |
| 6 | + |
| 7 | +rng = np.random.default_rng() |
5 | 8 |
|
6 | 9 |
|
7 | 10 | class PitchClass:
|
@@ -265,6 +268,57 @@ def plot(self, kind="area", save=False):
|
265 | 268 | if save:
|
266 | 269 | plt.savefig(save)
|
267 | 270 |
|
| 271 | + def play( |
| 272 | + self, |
| 273 | + mode: str = "cloud", |
| 274 | + n_notes: int = 100, |
| 275 | + note_duration: float = 0.15, |
| 276 | + velocity: int = 100, |
| 277 | + instrument_name: str = "Acoustic Grand Piano", |
| 278 | + save_as: str = None, |
| 279 | + ): |
| 280 | + |
| 281 | + if mode == "cloud": |
| 282 | + starts = np.arange(n_notes) * note_duration # onsets |
| 283 | + ends = starts + note_duration # offsets |
| 284 | + |
| 285 | + pitches = [x for x in rng.choice(np.nonzero(self.to_vector())[0], size=n_notes)] |
| 286 | + octaves = rng.choice(np.arange(3, 7), size=n_notes) |
| 287 | + midi_pitches = [(p + 12 * o) for p, o in list(zip(pitches, octaves))] |
| 288 | + elif mode == "chord": |
| 289 | + pitches = self.pcs |
| 290 | + octaves = [4] * pitches.shape[0] |
| 291 | + midi_pitches = [(p + 12 * o) for p, o in list(zip(pitches, octaves))] |
| 292 | + |
| 293 | + starts = [0] * pitches.shape[0] |
| 294 | + ends = [note_duration] * pitches.shape[0] |
| 295 | + |
| 296 | + # Create a PrettyMIDI object |
| 297 | + midi = pm.PrettyMIDI() |
| 298 | + |
| 299 | + # Create an Instrument instance for an instrument |
| 300 | + assert ( |
| 301 | + instrument_name in pm.constants.INSTRUMENT_MAP |
| 302 | + ), f"Instrument must be in {pm.constants.INSTRUMENT_MAP}" |
| 303 | + # instrument_code = pm.constants.INSTRUMENT_MAP.index(instrument_name) |
| 304 | + |
| 305 | + program = pm.instrument_name_to_program(instrument_name) |
| 306 | + instrument = pm.Instrument(program=program) |
| 307 | + |
| 308 | + for mp, s, e in zip(midi_pitches, starts, ends): |
| 309 | + # Create a Note instance for this note, starting at `s` and ending at `e`. |
| 310 | + note = pm.Note(pitch=mp, velocity=velocity, start=s, end=e) |
| 311 | + # Add it to instrument |
| 312 | + instrument.notes.append(note) |
| 313 | + |
| 314 | + # Add the instrument to the PrettyMIDI object |
| 315 | + midi.instruments.append(instrument) |
| 316 | + |
| 317 | + if save_as is not None: |
| 318 | + midi.write(save_as) |
| 319 | + else: |
| 320 | + return midi |
| 321 | + |
268 | 322 | def info(self):
|
269 | 323 | print("=" * len(repr(self)))
|
270 | 324 | print(repr(self))
|
@@ -308,12 +362,14 @@ def info(self):
|
308 | 362 | # s = {0,1,2}
|
309 | 363 | s = "147T"
|
310 | 364 | s = "02479"
|
311 |
| - # s = {6,9,2} |
| 365 | + s = {6, 9, 2} |
312 | 366 | # s = {7, 10, 1, 5}
|
313 | 367 | # s = [0, 1, 6, 7, 5, 2, 4, 3, 10, 9, 11, 8] # 12-tone row
|
314 | 368 |
|
315 | 369 | pcset = PitchClassSet(s)
|
316 | 370 | pcset.info()
|
317 | 371 |
|
318 |
| - ax = pcset.plot(kind="area") |
319 |
| - plt.show() |
| 372 | + # ax = pcset.plot(kind="area") |
| 373 | + # plt.show() |
| 374 | + |
| 375 | + pcset.play(save_as="test.mid", mode="chord") |
0 commit comments