Melody Engine API

Package Overview

The melody_engine package re-exports the main public classes and functions from the engine submodules. The detailed API reference below documents those submodules directly so the type index stays unambiguous.

Structure Module

class melody_engine.structure.TimeSignature(beats_per_bar: 'int', beat_unit: 'int')[source]

Bases: object

beats_per_bar: int
beat_unit: int
classmethod from_string(value: str) TimeSignature[source]
property bar_length: float
class melody_engine.structure.NoteEvent(scale_step: 'int', duration: 'float', chromatic_adjustment: 'int' = 0, is_rest: 'bool' = False)[source]

Bases: object

scale_step: int
duration: float
chromatic_adjustment: int = 0
is_rest: bool = False
transpose_diatonic(step_shift: int) NoteEvent[source]
class melody_engine.structure.NoteCandidate(scale_step: 'int', chromatic_adjustment: 'int' = 0, is_rest: 'bool' = False)[source]

Bases: object

scale_step: int
chromatic_adjustment: int = 0
is_rest: bool = False
class melody_engine.structure.VoiceProfile(name: 'str', range_min: 'int', range_max: 'int', tessitura_min: 'int', tessitura_max: 'int', clef_hint: 'str | None' = None)[source]

Bases: object

name: str
range_min: int
range_max: int
tessitura_min: int
tessitura_max: int
clef_hint: str | None = None
property melodic_span: int
class melody_engine.structure.FormSection(label: 'str', start_bar: 'int', end_bar: 'int', role: 'str', source_bar: 'int | None' = None, transform: 'str' = 'free')[source]

Bases: object

label: str
start_bar: int
end_bar: int
role: str
source_bar: int | None = None
transform: str = 'free'
class melody_engine.structure.FormPlan(kind: 'str', sections: 'tuple[FormSection, ...]' = ())[source]

Bases: object

kind: str
sections: tuple[FormSection, ...] = ()
section_for_bar(bar_number: int) FormSection | None[source]
class melody_engine.structure.ChoralePlan(voice_profiles: 'tuple[VoiceProfile, ...]' = ())[source]

Bases: object

voice_profiles: tuple[VoiceProfile, ...] = ()
class melody_engine.structure.Motif(events: 'tuple[NoteEvent, ...]', name: 'str' = 'motif')[source]

Bases: object

events: tuple[NoteEvent, ...]
name: str = 'motif'
classmethod from_steps(scale_steps: list[int], durations: list[float], name: str = 'motif') Motif[source]
property length: float
transpose_diatonic(step_shift: int) Motif[source]
class melody_engine.structure.HarmonySpan(start_bar: 'int', end_bar: 'int', roman_symbol: 'str', weight: 'float' = 1.0, start_beat: 'float' = 0.0, end_beat: 'float | None' = None)[source]

Bases: object

start_bar: int
end_bar: int
roman_symbol: str
weight: float = 1.0
start_beat: float = 0.0
end_beat: float | None = None
covers(bar_number: int, beat_in_bar: float, bar_length: float) bool[source]
overlaps_bar(bar_number: int) bool[source]
class melody_engine.structure.HarmonyPlan(spans: 'tuple[HarmonySpan, ...]' = ())[source]

Bases: object

spans: tuple[HarmonySpan, ...] = ()
chord_for_bar(bar_number: int) HarmonySpan | None[source]
chord_for_position(bar_number: int, beat_in_bar: float, bar_length: float) HarmonySpan | None[source]
class melody_engine.structure.Melody(key: 'Key', time_signature: 'TimeSignature', events: 'tuple[NoteEvent, ...]', harmony_plan: 'HarmonyPlan' = HarmonyPlan(spans=()), clef: 'str | None' = None, voice_profile: 'VoiceProfile' = VoiceProfile(name='melody', range_min=0, range_max=9, tessitura_min=1, tessitura_max=8, clef_hint=None), metadata: 'dict[str, object]' = <factory>)[source]

Bases: object

key: Key
time_signature: TimeSignature
events: tuple[NoteEvent, ...]
harmony_plan: HarmonyPlan = HarmonyPlan(spans=())
clef: str | None = None
voice_profile: VoiceProfile = VoiceProfile(name='melody', range_min=0, range_max=9, tessitura_min=1, tessitura_max=8, clef_hint=None)
metadata: dict[str, object]
property pitched_events: tuple[NoteEvent, ...]
transpose_diatonic(step_shift: int) Melody[source]
transpose_parallel(new_key: Key) Melody[source]
class melody_engine.structure.ChoraleScore(key: 'Key', time_signature: 'TimeSignature', soprano: 'Melody', alto: 'Melody', tenor: 'Melody', bass: 'Melody', harmony_plan: 'HarmonyPlan' = <factory>, metadata: 'dict[str, object]' = <factory>)[source]

Bases: object

key: Key
time_signature: TimeSignature
soprano: Melody
alto: Melody
tenor: Melody
bass: Melody
harmony_plan: HarmonyPlan
metadata: dict[str, object]
property voices: tuple[Melody, Melody, Melody, Melody]
class melody_engine.structure.GenerationSettings(key: 'Key', time_signature: 'TimeSignature', bars: 'int', allowed_durations: 'tuple[float, ...]' = (0.5, 1.0, 2.0), range_min: 'int' = 0, range_max: 'int' = 9, motif: 'Motif | None' = None, motif_repetition_bar: 'int | None' = None, motif_repetition_shift: 'int' = 1, harmonic_plan: 'HarmonyPlan' = HarmonyPlan(spans=()), phrase_length_bars: 'int' = 4, cadence_duration: 'float' = 2.0, attempts: 'int' = 48, random_seed: 'int' = 7, form_plan: 'FormPlan' = FormPlan(kind='free', sections=()), clef: 'str | None' = None, texture: 'str' = 'melody', voice_profile: 'VoiceProfile' = VoiceProfile(name='melody', range_min=0, range_max=9, tessitura_min=1, tessitura_max=8, clef_hint=None), chorale_plan: 'ChoralePlan' = ChoralePlan(voice_profiles=()))[source]

Bases: object

key: Key
time_signature: TimeSignature
bars: int
allowed_durations: tuple[float, ...] = (0.5, 1.0, 2.0)
range_min: int = 0
range_max: int = 9
motif: Motif | None = None
motif_repetition_bar: int | None = None
motif_repetition_shift: int = 1
harmonic_plan: HarmonyPlan = HarmonyPlan(spans=())
phrase_length_bars: int = 4
cadence_duration: float = 2.0
attempts: int = 48
random_seed: int = 7
form_plan: FormPlan = FormPlan(kind='free', sections=())
clef: str | None = None
texture: str = 'melody'
voice_profile: VoiceProfile = VoiceProfile(name='melody', range_min=0, range_max=9, tessitura_min=1, tessitura_max=8, clef_hint=None)
chorale_plan: ChoralePlan = ChoralePlan(voice_profiles=())

Theory Module

melody_engine.theory.parse_pitch_class(note_name: str) int[source]
melody_engine.theory.accidental_suffix(accidental: int) str[source]
melody_engine.theory.accidental_value(symbol: str) int[source]
melody_engine.theory.lilypond_octave(octave: int) str[source]
melody_engine.theory.normalize_roman_symbol(symbol: str) str[source]
melody_engine.theory.roman_symbol_accidental(symbol: str) int[source]
melody_engine.theory.roman_symbol_quality(symbol: str) str[source]
melody_engine.theory.split_spelling(spelling: str) tuple[str, int][source]
class melody_engine.theory.Key(tonic: 'str', mode: 'str' = 'major', tonic_octave: 'int' = 4)[source]

Bases: object

tonic: str
mode: str = 'major'
tonic_octave: int = 4
property tonic_pitch_class: int
property scale_intervals: tuple[int, ...]
property scale_spellings: tuple[str, ...]
lilypond_pitch(scale_step: int) str[source]
chromatic_pitch(scale_step: int, chromatic_adjustment: int = 0) str[source]
absolute_midi(scale_step: int, chromatic_adjustment: int = 0) int[source]
scale_pitch_class(scale_step: int) int[source]
chord_tones(roman_symbol: str) tuple[int, int, int][source]
chord_pitch_classes(roman_symbol: str) tuple[int, int, int][source]
chord_scale_targets(roman_symbol: str) tuple[tuple[int, int], tuple[int, int], tuple[int, int]][source]

Constraints Module

class melody_engine.constraints.CandidateContext(key: 'Key', events: 'tuple[NoteEvent, ...]', index: 'int', bar_number: 'int', beat_in_bar: 'float', total_events: 'int', climax_index: 'int', climax_step: 'int', phrase_end_bars: 'frozenset[int]', current_duration: 'float', harmony_span: 'HarmonySpan | None' = None, motif_target_step: 'int | None' = None, section_role: 'str' = 'free', section_transform: 'str' = 'free')[source]

Bases: object

key: Key
events: tuple[NoteEvent, ...]
index: int
bar_number: int
beat_in_bar: float
total_events: int
climax_index: int
climax_step: int
phrase_end_bars: frozenset[int]
current_duration: float
harmony_span: HarmonySpan | None = None
motif_target_step: int | None = None
section_role: str = 'free'
section_transform: str = 'free'
property previous_event: NoteEvent | None
property previous_interval: int | None
property previous_pitched_event: NoteEvent | None
property previous_pitched_interval: int | None
property notes_since_last_rest: int
property candidate_is_final: bool
property on_strong_beat: bool
class melody_engine.constraints.SoftConstraint(*args, **kwargs)[source]

Bases: Protocol

name: str
weight: float
evaluate(candidate: NoteCandidate, context: CandidateContext) float[source]
class melody_engine.constraints.StepwiseMotionConstraint(weight: 'float' = 1.0, name: 'str' = 'stepwise_motion')[source]

Bases: object

weight: float = 1.0
name: str = 'stepwise_motion'
evaluate(candidate: NoteCandidate, context: CandidateContext) float[source]
class melody_engine.constraints.LeapRecoveryConstraint(weight: 'float' = 1.0, name: 'str' = 'leap_recovery')[source]

Bases: object

weight: float = 1.0
name: str = 'leap_recovery'
evaluate(candidate: NoteCandidate, context: CandidateContext) float[source]
class melody_engine.constraints.LeadingToneResolutionConstraint(weight: 'float' = 1.0, name: 'str' = 'leading_tone_resolution')[source]

Bases: object

weight: float = 1.0
name: str = 'leading_tone_resolution'
evaluate(candidate: NoteCandidate, context: CandidateContext) float[source]
class melody_engine.constraints.ChordTonePreferenceConstraint(weight: 'float' = 1.0, non_chord_tone_penalty: 'float' = -0.35, name: 'str' = 'chord_tone_preference')[source]

Bases: object

weight: float = 1.0
non_chord_tone_penalty: float = -0.35
name: str = 'chord_tone_preference'
evaluate(candidate: NoteCandidate, context: CandidateContext) float[source]
class melody_engine.constraints.StrongBeatStabilityConstraint(weight: 'float' = 1.0, name: 'str' = 'strong_beat_stability')[source]

Bases: object

weight: float = 1.0
name: str = 'strong_beat_stability'
evaluate(candidate: NoteCandidate, context: CandidateContext) float[source]
class melody_engine.constraints.PhraseCadenceConstraint(weight: 'float' = 1.0, name: 'str' = 'phrase_cadence')[source]

Bases: object

weight: float = 1.0
name: str = 'phrase_cadence'
evaluate(candidate: NoteCandidate, context: CandidateContext) float[source]
class melody_engine.constraints.SingleClimaxConstraint(weight: 'float' = 1.0, name: 'str' = 'single_climax')[source]

Bases: object

weight: float = 1.0
name: str = 'single_climax'
evaluate(candidate: NoteCandidate, context: CandidateContext) float[source]
class melody_engine.constraints.MotifPreferenceConstraint(weight: 'float' = 1.0, name: 'str' = 'motif_preference')[source]

Bases: object

weight: float = 1.0
name: str = 'motif_preference'
evaluate(candidate: NoteCandidate, context: CandidateContext) float[source]
class melody_engine.constraints.RepeatedPitchConstraint(weight: 'float' = 1.0, name: 'str' = 'repeated_pitch_control')[source]

Bases: object

weight: float = 1.0
name: str = 'repeated_pitch_control'
evaluate(candidate: NoteCandidate, context: CandidateContext) float[source]
class melody_engine.constraints.DirectionChangeConstraint(weight: 'float' = 1.0, name: 'str' = 'direction_change')[source]

Bases: object

weight: float = 1.0
name: str = 'direction_change'
evaluate(candidate: NoteCandidate, context: CandidateContext) float[source]
class melody_engine.constraints.LargeLeapConstraint(weight: 'float' = 1.0, name: 'str' = 'large_leap')[source]

Bases: object

weight: float = 1.0
name: str = 'large_leap'
evaluate(candidate: NoteCandidate, context: CandidateContext) float[source]
class melody_engine.constraints.RestConstraint(weight: 'float' = 1.0, name: 'str' = 'rest_usage')[source]

Bases: object

weight: float = 1.0
name: str = 'rest_usage'
evaluate(candidate: NoteCandidate, context: CandidateContext) float[source]
class melody_engine.constraints.FormSectionConstraint(weight: 'float' = 1.0, name: 'str' = 'form_section')[source]

Bases: object

weight: float = 1.0
name: str = 'form_section'
evaluate(candidate: NoteCandidate, context: CandidateContext) float[source]

Generator Module

class melody_engine.generator.GenerationAttempt(events: 'tuple[NoteEvent, ...]', score: 'float')[source]

Bases: object

events: tuple[NoteEvent, ...]
score: float
class melody_engine.generator.MelodyGenerator(settings: GenerationSettings, constraints: list[SoftConstraint])[source]

Bases: object

generate() Melody[source]

LilyPond Module

melody_engine.lilypond.lilypond_duration(duration: float) str[source]
melody_engine.lilypond.lilypond_key_name(tonic: str) str[source]
melody_engine.lilypond.choose_clef(melody: Melody) str[source]
melody_engine.lilypond.melody_to_lilypond_source(melody: Melody) str[source]
melody_engine.lilypond.note_token(melody: Melody, event) str[source]
melody_engine.lilypond.voice_music_body(melody: Melody) str[source]
melody_engine.lilypond.export_melody(melody: Melody, output_path: str | Path) Path[source]
melody_engine.lilypond.chorale_to_lilypond_source(score: ChoraleScore) str[source]
melody_engine.lilypond.export_chorale(score: ChoraleScore, output_path: str | Path) Path[source]
melody_engine.lilypond.render_lilypond_file(source_path: str | Path, output_dir: str | Path | None = None, *, cropped: bool = False, lilypond_bin: str = 'lilypond') list[Path][source]
melody_engine.lilypond.render_audio_from_midi(midi_path: str | Path, wav_path: str | Path | None = None, *, timidity_bin: str = 'timidity') Path[source]
melody_engine.lilypond.render_sources(sources: list[Path], *, output_dir: Path | None = None, pdf: bool = False, wav: bool = False, lilypond_bin: str = 'lilypond', timidity_bin: str = 'timidity') list[Path][source]