From 78c529acb98ad7e0dab756545ea226b5877f6432 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Wed, 1 Apr 2026 13:21:03 -0400 Subject: [PATCH] The Interruption: 32nd note hat fills, fix play.py --from-time counter Hat fills every 4 bars, bigger fills every 8. Play counter now shows correct time when using --from-time. Co-Authored-By: Claude Opus 4.6 (1M context) --- play.py | 18 +++++++++++------- tracks/the_interruption.py | 35 +++++++++++++++++++++++++++++++---- 2 files changed, 42 insertions(+), 11 deletions(-) diff --git a/play.py b/play.py index 9626f44..a1baddc 100644 --- a/play.py +++ b/play.py @@ -212,6 +212,8 @@ def render_audio(score, *, from_measure=None, to_measure=None, start = int(max(0, min(start, len(buf)))) end = int(max(start, min(end, len(buf)))) + offset_sec = start / sample_rate + if start > 0 or end < len(buf): buf = buf[start:end] @@ -219,17 +221,18 @@ def render_audio(score, *, from_measure=None, to_measure=None, import numpy buf = numpy.tile(buf, (loop, 1)) if buf.ndim == 2 else numpy.tile(buf, loop) - return buf, sample_rate + return buf, sample_rate, offset_sec -def play_audio(buf, sample_rate, title="", info_lines=None): +def play_audio(buf, sample_rate, title="", info_lines=None, offset_sec=0.0): """Simple terminal playback with progress bar.""" import sounddevice as sd import time total_frames = len(buf) total_sec = total_frames / sample_rate - tot_m, tot_s = int(total_sec // 60), int(total_sec % 60) + full_sec = total_sec + offset_sec + tot_m, tot_s = int(full_sec // 60), int(full_sec % 60) if title: print(f"\n {title}") @@ -242,9 +245,10 @@ def play_audio(buf, sample_rate, title="", info_lines=None): try: sd.play(buf, sample_rate) while sd.get_stream().active: - cur_sec = time.monotonic() - start + elapsed = time.monotonic() - start + cur_sec = elapsed + offset_sec cur_m, cur_s = int(cur_sec // 60), int(cur_sec % 60) - pct = min(1.0, cur_sec / total_sec) if total_sec > 0 else 0 + pct = min(1.0, cur_sec / full_sec) if full_sec > 0 else 0 bar_w = 40 filled = int(pct * bar_w) bar = "█" * filled + "░" * (bar_w - filled) @@ -600,7 +604,7 @@ def main(): from_sec = parse_time(args.from_time) if args.from_time else None to_sec = parse_time(args.to_time) if args.to_time else None - buf, sr = render_audio( + buf, sr, offset_sec = render_audio( score, from_measure=args.from_measure, to_measure=args.to_measure, @@ -632,7 +636,7 @@ def main(): parts += " — " + " ".join(extras) info.append(parts) - play_audio(buf, sr, title=title, info_lines=info) + play_audio(buf, sr, title=title, info_lines=info, offset_sec=offset_sec) if __name__ == "__main__": diff --git a/tracks/the_interruption.py b/tracks/the_interruption.py index 790eb97..401c36b 100644 --- a/tracks/the_interruption.py +++ b/tracks/the_interruption.py @@ -342,10 +342,37 @@ for _ in range(32): # Classic amen-style break for bar in range(32): if bar % 8 == 7: - # Fill — snare rolls - for i in range(16): - vel = min(127, 70 + i * 3) - beat.hit(S, Duration.SIXTEENTH, velocity=vel) + # Fill — snare into 32nd note hat cascade + beat.hit(S, Duration.SIXTEENTH, velocity=108) + beat.hit(S, Duration.SIXTEENTH, velocity=105) + beat.hit(K, Duration.SIXTEENTH, velocity=110) + beat.hit(S, Duration.SIXTEENTH, velocity=100) + # 32nd note hat roll + for i in range(8): + vel = min(127, 55 + i * 8) + beat.hit(CH, 0.125, velocity=vel) + # Back to snare hits + beat.hit(S, Duration.SIXTEENTH, velocity=112) + beat.hit(K, Duration.SIXTEENTH, velocity=115) + beat.hit(S, Duration.SIXTEENTH, velocity=118) + beat.hit(S, Duration.SIXTEENTH, velocity=120) + elif bar % 4 == 3: + # Mini fill — 32nd hat flurry on beat 4 + beat.hit(K, Duration.SIXTEENTH, velocity=110) + beat.hit(CH, Duration.SIXTEENTH, velocity=50) + beat.hit(CH, Duration.SIXTEENTH, velocity=45) + beat.hit(CH, Duration.SIXTEENTH, velocity=48) + beat.hit(S, Duration.SIXTEENTH, velocity=105) + beat.hit(CH, Duration.SIXTEENTH, velocity=50) + beat.hit(CH, Duration.SIXTEENTH, velocity=42) + beat.hit(K, Duration.SIXTEENTH, velocity=95) + beat.hit(CH, Duration.SIXTEENTH, velocity=48) + beat.hit(K, Duration.SIXTEENTH, velocity=100) + beat.hit(S, Duration.SIXTEENTH, velocity=108) + beat.hit(CH, Duration.SIXTEENTH, velocity=45) + # 32nd note hat burst + for i in range(8): + beat.hit(CH, 0.125, velocity=min(90, 50 + i * 5)) else: # K---S--K-KS---- beat.hit(K, Duration.SIXTEENTH, velocity=110)