Spaces:
Sleeping
Sleeping
"""Module for handling melody generation and playback.""" | |
from dataclasses import dataclass | |
from typing import List, Optional | |
from improvisation_lab.domain.composition.phrase_generator import \ | |
PhraseGenerator | |
from improvisation_lab.domain.music_theory import ChordTone | |
class PhraseData: | |
"""Data structure containing information about a melodic phrase.""" | |
notes: List[str] | |
chord_name: str | |
scale_info: str | |
length: int | |
class MelodyComposer: | |
"""Class responsible for generating melodic phrases based on chord progressions.""" | |
def __init__(self): | |
"""Initialize MelodyPlayer with a melody generator.""" | |
self.phrase_generator = PhraseGenerator() | |
def generate_phrases( | |
self, progression: List[tuple[str, str, str, str, int]] | |
) -> List[PhraseData]: | |
"""Generate a sequence of melodic phrases based on a chord progression. | |
Args: | |
progression: | |
List of tuples containing (scale_root, scale_type, chord_root, | |
chord_type, length) for each chord in the progression. | |
Returns: | |
List of PhraseData objects containing the generated melodic phrases. | |
""" | |
phrases: List[PhraseData] = [] | |
prev_note: Optional[str] = None | |
prev_note_was_chord_tone = False | |
for scale_root, scale_type, chord_root, chord_type, length in progression: | |
phrase = self.phrase_generator.generate_phrase( | |
scale_root=scale_root, | |
scale_type=scale_type, | |
chord_root=chord_root, | |
chord_type=chord_type, | |
prev_note=prev_note, | |
prev_note_was_chord_tone=prev_note_was_chord_tone, | |
length=length, | |
) | |
# Update information for the next phrase | |
prev_note = phrase[-1] | |
prev_note_was_chord_tone = self.phrase_generator.is_chord_tone( | |
prev_note, ChordTone.get_chord_tones(chord_root, chord_type) | |
) | |
phrases.append( | |
PhraseData( | |
notes=phrase, | |
chord_name=f"{chord_root}{chord_type}", | |
scale_info=f"{scale_root} {scale_type}", | |
length=length, | |
) | |
) | |
return phrases | |