From c20a56efd0dc5da9cb20222a9136b07621f2fca4 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Mon, 30 Mar 2026 05:14:25 -0400 Subject: [PATCH] =?UTF-8?q?Track=205:=20Acid=20Reign=20=E2=80=94=20filthy?= =?UTF-8?q?=20303=20bass,=20A=20minor,=20135=20BPM?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Four acid patterns cycling with high-Q resonant filter sweep across the whole track. Saw + distortion + saturation + lowpass_q=4.0. Starts with 303 alone, kick enters bar 9, full energy bar 41, strips back to 303 alone at the end. Sub bass octave below. Co-Authored-By: Claude Opus 4.6 (1M context) --- tracks/acid_reign.py | 207 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 207 insertions(+) create mode 100644 tracks/acid_reign.py diff --git a/tracks/acid_reign.py b/tracks/acid_reign.py new file mode 100644 index 0000000..84e5e91 --- /dev/null +++ b/tracks/acid_reign.py @@ -0,0 +1,207 @@ +""" +ACID REIGN — the filthiest 303 bass line in human existence. +Squelchy, resonant, relentless. Filter sweeps that melt faces. +""" + +from pytheory import Key, Duration, Score, Tone, play_score +from pytheory.rhythm import DrumSound + +key = Key("A", "minor") +s = key.scale + +A = s[0]; B = s[1]; C = s[2]; D = s[3] +E = s[4]; F = s[5]; G = s[6] + +score = Score("4/4", bpm=135) + +K = DrumSound.KICK +CL = DrumSound.CLAP +CH = DrumSound.CLOSED_HAT +OH = DrumSound.OPEN_HAT + +# ═══════════════════════════════════════════════════════════════════ +# STRUCTURE (64 bars, ~3 min): +# Bars 1-8: Just the 303, alone. Raw. +# Bars 9-16: Kick enters. The groove locks. +# Bars 17-32: Full beat, filter opening, acid intensifying +# Bars 33-40: Breakdown — 303 goes mental, filter wide +# Bars 41-56: Peak — everything, filter sweeping wildly +# Bars 57-64: Outro — stripped back, 303 alone again +# ═══════════════════════════════════════════════════════════════════ + +# ── THE 303 — squelchy saw, high resonance, the whole point ───── +acid = score.part("303", synth="saw", envelope="pluck", volume=0.5, + lowpass=800, lowpass_q=4.0, + distortion=0.4, distortion_drive=5.0, + saturation=0.3, humanize=0.03) +# The filter sweep — slow open across the whole track +acid.lfo("lowpass", rate=0.015, min=400, max=8000, bars=64, shape="triangle") + +# The pattern — classic acid: 16th notes with slides and accents +# Mostly root and fifth with chromatic approach notes +acid_bars = [ + # Pattern A: driving root + [(A.add(-12), 100), (None, 0), (A.add(-12), 90), (E.add(-12), 85), + (A.add(-12), 95), (None, 0), (G.add(-24), 80), (A.add(-12), 100), + (None, 0), (A.add(-12), 88), (None, 0), (E.add(-12), 82), + (A.add(-12), 95), (G.add(-24), 78), (A.add(-12), 92), (None, 0)], + # Pattern B: climbing + [(A.add(-12), 95), (B.add(-12), 85), (C, 90), (None, 0), + (E, 100), (None, 0), (C, 88), (A.add(-12), 82), + (None, 0), (G.add(-24), 78), (A.add(-12), 95), (None, 0), + (C, 92), (E, 98), (C, 85), (A.add(-12), 90)], + # Pattern C: menacing + [(A.add(-12), 100), (None, 0), (None, 0), (A.add(-12), 105), + (Tone.from_string("Ab2"), 90), (A.add(-12), 100), (None, 0), (E.add(-12), 88), + (None, 0), (None, 0), (A.add(-12), 95), (Tone.from_string("Bb2"), 85), + (A.add(-12), 100), (None, 0), (G.add(-24), 80), (A.add(-12), 98)], + # Pattern D: wild — big intervals + [(A.add(-12), 105), (E, 95), (A.add(-12), 100), (None, 0), + (C, 92), (None, 0), (A.add(-12), 98), (E, 90), + (G.add(-24), 85), (A.add(-12), 100), (E, 95), (None, 0), + (C, 90), (A.add(-12), 102), (None, 0), (E, 95)], +] + +# Bars 1-8: just the 303 alone — pattern A and B +for _ in range(2): + for bar in acid_bars[:2]: + for note, vel in bar: + if note is None: + acid.rest(Duration.SIXTEENTH) + else: + acid.add(note, Duration.SIXTEENTH, velocity=vel) + +# Bars 9-16: patterns cycle +for bar in acid_bars: + for note, vel in bar: + if note is None: + acid.rest(Duration.SIXTEENTH) + else: + acid.add(note, Duration.SIXTEENTH, velocity=vel) +for bar in acid_bars: + for note, vel in bar: + if note is None: + acid.rest(Duration.SIXTEENTH) + else: + acid.add(note, Duration.SIXTEENTH, velocity=min(127, vel + 5)) + +# Bars 17-32: all patterns, louder +for _ in range(4): + for bar in acid_bars: + for note, vel in bar: + if note is None: + acid.rest(Duration.SIXTEENTH) + else: + acid.add(note, Duration.SIXTEENTH, velocity=min(127, vel + 10)) + +# Bars 33-40: breakdown — 303 goes mental, pattern D repeated +for _ in range(8): + for note, vel in acid_bars[3]: + if note is None: + acid.rest(Duration.SIXTEENTH) + else: + acid.add(note, Duration.SIXTEENTH, velocity=min(127, vel + 15)) + +# Bars 41-56: peak — cycling all patterns at max +for _ in range(4): + for bar in acid_bars: + for note, vel in bar: + if note is None: + acid.rest(Duration.SIXTEENTH) + else: + acid.add(note, Duration.SIXTEENTH, velocity=min(127, vel + 15)) + +# Bars 57-64: just the 303 again, filtering down +for _ in range(2): + for bar in acid_bars[:2]: + for note, vel in bar: + if note is None: + acid.rest(Duration.SIXTEENTH) + else: + acid.add(note, Duration.SIXTEENTH, velocity=max(40, vel - 20)) + +# ── KICK — four on the floor, enters bar 9 ───────────────────── +kick = score.part("kick", volume=0.5, humanize=0.03) + +for _ in range(8): + kick.rest(Duration.WHOLE) + +for _ in range(48): + for beat in range(4): + kick.hit(K, Duration.QUARTER, velocity=115) + +# Bars 57-64: fading +for bar in range(8): + vel = max(30, 110 - bar * 10) + for beat in range(4): + kick.hit(K, Duration.QUARTER, velocity=vel) + +# ── CLAP — 2 and 4, enters bar 9 ────────────────────────────── +clap = score.part("clap", volume=0.3, reverb=0.15, humanize=0.04) + +for _ in range(8): + clap.rest(Duration.WHOLE) + +for _ in range(48): + clap.rest(Duration.QUARTER) + clap.hit(CL, Duration.QUARTER, velocity=95) + clap.rest(Duration.QUARTER) + clap.hit(CL, Duration.QUARTER, velocity=98) + +for bar in range(8): + vel = max(25, 90 - bar * 8) + clap.rest(Duration.QUARTER) + clap.hit(CL, Duration.QUARTER, velocity=vel) + clap.rest(Duration.QUARTER) + clap.hit(CL, Duration.QUARTER, velocity=vel) + +# ── HATS — 16th notes, open hat on offbeats, enters bar 17 ───── +hats = score.part("hats", volume=0.25, humanize=0.04) + +for _ in range(16): + hats.rest(Duration.WHOLE) + +for _ in range(40): + for beat in range(4): + hats.hit(CH, Duration.SIXTEENTH, velocity=75) + hats.hit(CH, Duration.SIXTEENTH, velocity=45) + hats.hit(OH if beat % 2 == 1 else CH, Duration.SIXTEENTH, velocity=60) + hats.hit(CH, Duration.SIXTEENTH, velocity=42) + +for bar in range(8): + vel = max(20, 70 - bar * 6) + for beat in range(4): + hats.hit(CH, Duration.SIXTEENTH, velocity=vel) + hats.hit(CH, Duration.SIXTEENTH, velocity=max(15, vel - 25)) + hats.hit(CH, Duration.SIXTEENTH, velocity=max(15, vel - 15)) + hats.hit(CH, Duration.SIXTEENTH, velocity=max(15, vel - 28)) + +# ── SUB BASS — octave below 303, just the root ───────────────── +sub = score.part("sub", synth="sine", envelope="pad", volume=0.3, + lowpass=80) + +for _ in range(8): + sub.rest(Duration.WHOLE) + +for _ in range(48): + sub.add(A.add(-36), Duration.WHOLE, velocity=90) + +for bar in range(8): + sub.add(A.add(-36), Duration.WHOLE, velocity=max(20, 85 - bar * 10)) + +# ═════════════════════════════════════════════════════════════════ +import sys + +print(f"Key: {key}") +print(f"BPM: 135") +print(f"Parts: {list(score.parts.keys())}") +print(f"Duration: {score.duration_ms / 1000:.1f}s | {score.measures} measures") + +if "--live" in sys.argv: + print("Playing ACID REIGN (live engine)...") + from pytheory_live.live import LiveEngine + engine = LiveEngine(buffer_size=1024) + engine.play_score(score) +else: + print("Playing ACID REIGN...") + play_score(score)