diff --git a/pytheory/play.py b/pytheory/play.py index 247b862..21a3555 100644 --- a/pytheory/play.py +++ b/pytheory/play.py @@ -1971,7 +1971,8 @@ def _render_notes_to_buf(notes, buf, samples_per_beat, total_samples, filter_attack=0.01, filter_decay=0.3, filter_sustain=0.0, filter_amount=0.0, vel_to_filter=0.0, filter_q=0.707, - synth_kwargs=None, temperament="equal"): + synth_kwargs=None, temperament="equal", + reference_pitch=440.0): """Render a list of Notes into an existing buffer at the correct positions.""" import random as _rnd @@ -2000,9 +2001,9 @@ def _render_notes_to_buf(notes, buf, samples_per_beat, total_samples, if n_samples > 0 and start >= 0: # Get pitches if hasattr(note.tone, 'tones'): - pitches = [t.pitch(temperament=temperament) for t in note.tone.tones] + pitches = [t.pitch(temperament=temperament, reference_pitch=reference_pitch) for t in note.tone.tones] else: - pitches = [note.tone.pitch(temperament=temperament)] + pitches = [note.tone.pitch(temperament=temperament, reference_pitch=reference_pitch)] # Render oscillators (pass synth_kwargs for FM etc.) waves = [synth_fn(hz, n_samples=n_samples, **_skw) for hz in pitches] @@ -2088,7 +2089,7 @@ def _render_notes_to_buf(notes, buf, samples_per_beat, total_samples, def _render_legato_to_buf(notes, buf, samples_per_beat, total_samples, synth_fn, envelope_tuple, volume, bpm, glide_time=0.0, swing=0.0, tempo_map=None, - temperament="equal"): + temperament="equal", reference_pitch=440.0): """Render notes as one continuous waveform with pitch glide. Instead of rendering each note separately with its own envelope, @@ -2118,9 +2119,9 @@ def _render_legato_to_buf(notes, buf, samples_per_beat, total_samples, vel = getattr(note, 'velocity', 100) if note.tone is not None: if hasattr(note.tone, 'tones'): - hz = note.tone.tones[0].pitch(temperament=temperament) + hz = note.tone.tones[0].pitch(temperament=temperament, reference_pitch=reference_pitch) else: - hz = note.tone.pitch(temperament=temperament) + hz = note.tone.pitch(temperament=temperament, reference_pitch=reference_pitch) events.append((start, end, hz, vel)) else: events.append((start, end, 0, vel)) # rest @@ -2239,13 +2240,14 @@ def render_score(score): synth_kwargs["mod_ratio"] = part.fm_ratio synth_kwargs["mod_index"] = part.fm_index _temperament = getattr(score, 'temperament', 'equal') + _ref_pitch = getattr(score, 'reference_pitch', 440.0) if part.legato: _render_legato_to_buf( part.notes, part_buf, samples_per_beat, total_samples, synth_fn, env_tuple, part.volume, score.bpm, glide_time=part.glide, swing=effective_swing, tempo_map=tempo_map if has_tempo_changes else None, - temperament=_temperament) + temperament=_temperament, reference_pitch=_ref_pitch) else: _render_notes_to_buf( part.notes, part_buf, samples_per_beat, total_samples, @@ -2265,7 +2267,8 @@ def render_score(score): vel_to_filter=part.vel_to_filter, filter_q=part.lowpass_q, synth_kwargs=synth_kwargs, - temperament=_temperament) + temperament=_temperament, + reference_pitch=_ref_pitch) # Apply effects — segmented if automation exists auto_points = part._get_automation_points() diff --git a/pytheory/rhythm.py b/pytheory/rhythm.py index 66ef01b..a08766b 100644 --- a/pytheory/rhythm.py +++ b/pytheory/rhythm.py @@ -2074,7 +2074,7 @@ class Score: def __init__(self, time_signature="4/4", bpm=120, swing: float = 0.0, drum_humanize: float = 0.15, system: str = "western", - temperament: str = "equal"): + temperament: str = "equal", reference_pitch: float = 440.0): if isinstance(time_signature, str): self.time_signature = TimeSignature.from_string(time_signature) else: @@ -2083,6 +2083,7 @@ class Score: self.swing = swing self.system = system self.temperament = temperament + self.reference_pitch = reference_pitch self._drum_humanize = drum_humanize self.notes: list[Note] = [] self.parts: dict[str, Part] = {}