Drums ===== Drums are the foundation of almost everything. Change the drum pattern and you change the genre. The same four chords over a bossa nova pattern sound like you're in a cafe in Rio. Put those same chords over a rock beat and you're in a garage in Seattle. Over a trap beat, you're in Atlanta. Over a dancehall pattern, you're in Kingston. The drums ARE the genre -- they tell the listener's body how to move before a single melodic note is played. PyTheory includes a complete drum system -- 27 synthesized percussion sounds, 58 pattern presets across dozens of genres, and 21 fill presets. Every sound is generated from waveforms; no samples needed. Drum Sounds ----------- Drum hits are **humanized by default** — each hit gets a tiny random timing offset and velocity wobble, just like a real drummer who's never perfectly on the grid. Control the amount with ``drum_humanize`` on the Score: .. code-block:: python score = Score("4/4", bpm=120, drum_humanize=0.4) # natural feel score = Score("4/4", bpm=120, drum_humanize=0.0) # perfectly quantized score = Score("4/4", bpm=120, drum_humanize=0.1) # studio tight The default is 0.15 — just enough to feel alive without sounding loose. Drums Are Parts ~~~~~~~~~~~~~~~~ Drums are a real Part — the same as any melodic voice. You can set effects on them the same way: .. code-block:: python score.drums("rock", repeats=4) score.parts["drums"].reverb_mix = 0.2 score.parts["drums"].reverb_type = "plate" Or use the shorthand: .. code-block:: python score.set_drum_effects(reverb=0.2, reverb_type="plate", lowpass=8000) Split Drums ~~~~~~~~~~~ For maximum control, split the kit into separate Parts — kick, snare, hats, toms, cymbals, and percussion — each with independent effects: .. code-block:: python score.drums("rock", repeats=4, split=True) # Now each group is its own Part score.parts["snare"].reverb_mix = 0.3 score.parts["snare"].reverb_type = "plate" score.parts["hats"].lowpass = 7000 score.parts["kick"] # dry, no effects # set_drum_effects still works — applies to all drum Parts score.set_drum_effects(reverb=0.1) This is how real studios work — the snare gets its own reverb send, the hats get their own EQ, the kick stays dry and punchy. Now you can do the same thing in Python. Sidechain compression triggers on kick hits only — hi-hats and snares don't duck the pad. Every drum sound is stereo-panned like a real kit — kick and snare center, hi-hat right, crash left, toms spread across the field, percussion instruments placed naturally. Put on headphones and you'll hear the kit in front of you. The ``DrumSound`` enum maps to General MIDI percussion note numbers: .. code-block:: pycon >>> from pytheory import DrumSound >>> DrumSound.KICK.value 36 >>> DrumSound.SNARE.value 38 >>> DrumSound.CLOSED_HAT.value 42 All 27 sounds, organized by type: **Kicks:** KICK (36) **Snares:** SNARE (38), RIMSHOT (37), CLAP (39) **Hi-hats:** CLOSED_HAT (42), OPEN_HAT (46), PEDAL_HAT (44) **Toms:** LOW_TOM (45), MID_TOM (47), HIGH_TOM (50) **Cymbals:** CRASH (49), RIDE (51), RIDE_BELL (53) **Percussion:** COWBELL (56), CLAVE (75), SHAKER (70), TAMBOURINE (54), CONGA_HIGH (63), CONGA_LOW (64), BONGO_HIGH (60), BONGO_LOW (61), TIMBALE_HIGH (65), TIMBALE_LOW (66), AGOGO_HIGH (67), AGOGO_LOW (68), GUIRO (73), MARACAS (70) Drum Synthesis -------------- Every drum sound here is synthesized from scratch using the same techniques that real drum machines use. This isn't a shortcut -- it's the real thing. The 808 kick that defined hip hop is literally a sine wave with a pitch envelope sweeping from 150 Hz down to 50 Hz. The 909 snare that powered techno is a sine wave body mixed with white noise rattle. The hi-hat is just filtered noise with a short decay. When Roland built the TR-808 and TR-909, they weren't sampling real drums; they were synthesizing them from basic waveforms. PyTheory does the same thing. Each sound has a dedicated synthesizer: - **KICK** -- sine wave with pitch envelope sweep (150 to 50 Hz) + sub click - **SNARE** -- pitched body (180 Hz) + white noise rattle - **CLOSED_HAT** -- high-frequency noise, 50ms decay - **OPEN_HAT** -- high-frequency noise, 250ms decay - **CLAP** -- layered noise bursts with spacers - **RIMSHOT** -- bright 800 Hz click + noise - **TOMS** -- pitched sine with sweep (low=100, mid=150, high=200 Hz) - **CRASH** -- long noise decay (1.5s) - **RIDE** -- metallic ring (3500+5100 Hz) + noise - **RIDE_BELL** -- brighter ring, more sustain - **COWBELL** -- two detuned tones (545+815 Hz) - **CLAVE** -- short 2500 Hz click - **CONGAS/BONGOS** -- pitched membrane with slap transient - **TIMBALES** -- bright metallic ring with overtones - **AGOGO** -- pitched bell with harmonics - **SHAKER/MARACAS** -- short noise burst - **TAMBOURINE** -- noise + 7000 Hz jingle ring - **GUIRO** -- scraped noise bursts Pattern Presets --------------- 58 patterns spanning genres from rock to Afro-Cuban to electronic. Load them with ``Pattern.preset()``: .. code-block:: pycon >>> from pytheory import Pattern >>> Pattern.list_presets() ['12/8 blues', '6/8 afro-cuban', 'afrobeat', 'baiao', 'bebop', ...] >>> rock = Pattern.preset("rock") >>> rock **Rock/Pop:** rock, half time, double time, disco, motown, train beat -- The backbone of Western popular music. Kick on 1 and 3, snare on 2 and 4. Simple, effective, universal. **Jazz:** jazz, bebop, shuffle, swing, linear, paradiddle -- The ride cymbal drives everything. The kick and snare comp and converse rather than keeping strict time. These patterns swing. **Latin:** salsa, bossa nova, samba, cumbia, merengue, baiao, maracatu, bolero, tango -- Rich, layered patterns built on clave rhythms, with congas, timbales, and shakers creating interlocking polyrhythmic webs. Some of the most sophisticated drumming traditions on the planet. **Afro-Cuban:** son clave 3-2, son clave 2-3, rumba clave 3-2, rumba clave 2-3, cascara, guaguanco, mozambique, nanigo, bembe, 6/8 afro-cuban, tresillo, habanera -- The clave is the key that unlocks all Latin and Afro-Cuban music. It's a five-note rhythmic cell that everything else revolves around. If you learn one concept from world music, learn the clave. **African:** afrobeat, highlife -- Born in West Africa. Fela Kuti's afrobeat layers multiple percussion voices into hypnotic, polyrhythmic grooves that can go on for twenty minutes. **Caribbean:** reggae, dancehall, ska, dub -- The offbeat is king. Reggae flips rock drumming inside out by emphasizing the "and" of each beat instead of the beat itself. Ska doubles the tempo, dancehall adds syncopation. **Electronic:** house, techno, trap, drum and bass, breakbeat, jungle -- Machine music. The four-on-the-floor kick of house and techno, the rattling hi-hats of trap, the breakneck tempo of drum and bass. These patterns were born in drum machines and they still live there. **Metal/Punk:** metal, blast beat, punk -- Speed and aggression. The blast beat is both feet and both hands going as fast as humanly possible. Punk strips everything to its essentials. **Other:** funk, hip hop, bo diddley, second line, new orleans, waltz, 12/8 blues, country, gospel, flamenco -- Everything else. The syncopated groove of funk, the sampled feel of hip hop, the street-parade swing of New Orleans second line. Playing Patterns ---------------- ``play_pattern()`` synthesizes every drum sound in real-time: .. code-block:: python from pytheory import Pattern from pytheory.play import play_pattern play_pattern(Pattern.preset("rock"), repeats=4, bpm=120) play_pattern(Pattern.preset("bossa nova"), repeats=4, bpm=140) play_pattern(Pattern.preset("salsa"), repeats=4, bpm=180) play_pattern(Pattern.preset("afrobeat"), repeats=8, bpm=110) Fills ----- A fill is the drummer's way of saying "something's about to change." It's that moment at the end of a verse where the drummer breaks the pattern and rolls around the toms before crashing into the chorus. Fills signal transitions -- they tell the listener's ear that the section is ending and a new one is about to begin. Without fills, a drum pattern just loops. With them, it breathes and has structure. ``Pattern.fill()`` loads a 1-bar drum fill -- a short break that transitions between sections. 21 fill presets are available: .. code-block:: pycon >>> Pattern.list_fills() ['afrobeat', 'blast', 'bossa nova', 'breakdown', 'buildup', 'cumbia', 'disco', 'funk', 'highlife', 'hip hop', 'house', 'jazz', 'jazz brush', 'metal', 'reggae', 'rock', 'rock crash', 'salsa', 'samba', 'second line', 'trap'] >>> fill = Pattern.fill("rock") >>> fill Score Integration ----------------- The ``score.drums()`` shorthand attaches a drum pattern to a score: .. code-block:: python from pytheory import Score score = Score("4/4", bpm=140) score.drums("bossa nova", repeats=4) Auto-Fills ~~~~~~~~~~ The ``fill`` and ``fill_every`` parameters automatically insert drum fills at regular intervals: .. code-block:: python score = Score("4/4", bpm=120) score.drums("rock", repeats=8, fill="rock", fill_every=4) This plays the rock pattern for 8 bars, replacing every 4th bar with a rock fill. Useful for adding natural phrasing to longer sections. .. code-block:: python # Jazz with brush fills every 8 bars score.drums("bebop", repeats=16, fill="jazz brush", fill_every=8) # Salsa with fills every 4 bars score.drums("salsa", repeats=8, fill="salsa", fill_every=4) Layering Patterns ----------------- Combine drum patterns with melodic parts for full arrangements. The drum pattern and all named parts are mixed together by ``play_score()``: .. code-block:: python from pytheory import Score, Key, Duration, Chord from pytheory.play import play_score score = Score("4/4", bpm=180) score.drums("salsa", repeats=4, fill="salsa", fill_every=4) pads = score.part("pads", synth="sine", envelope="pad", volume=0.3) lead = score.part("lead", synth="saw", envelope="pluck", volume=0.4) bass = score.part("bass", synth="sine", envelope="pluck", volume=0.45) for chord in Key("D", "minor").progression("ii", "V", "i", "i") * 2: pads.add(chord, Duration.WHOLE) lead.add("A5", 0.67).add("G5", 0.33).add("F5", 0.67).add("E5", 0.33) for n in ["D2", "A2", "D2", "F2"] * 2: bass.add(n, Duration.QUARTER) play_score(score) MIDI Export ----------- Convert any pattern to a Score, then export to MIDI (drums are written to channel 10): .. code-block:: python pattern = Pattern.preset("bossa nova") score = pattern.to_score(repeats=8, bpm=140) score.save_midi("bossa.mid") Pattern.preset("afrobeat").to_score(repeats=8, bpm=110).save_midi("afrobeat.mid") Drums are the foundation. The same chords over a bossa nova feel like a different song than over a rock beat -- change the pattern and you change the genre. Try swapping presets under the same progression and hear how much the drums are really doing.