Skip to content

API Reference

Complete reference for the beatstoch Python library.

Main Functions

generate_from_song()

Generate a MIDI drum pattern by looking up a song's BPM from the database.

generate_from_song(
    song_title: str,
    artist: Optional[str] = None,
    bars: int = 8,
    style: str = "house",
    steps_per_beat: int = 4,
    swing: float = 0.10,
    intensity: float = 0.9,
    seed: Optional[int] = None,
    fallback_bpm: Optional[float] = None,
    verbose: bool = False,
) -> Tuple[mido.MidiFile, float]

Parameters: - song_title (str): Title of the song to look up - artist (str, optional): Artist name for improved BPM lookup accuracy - bars (int): Number of bars to generate (default: 8) - style (str): Drum pattern style - "house", "breaks", or "generic" (default: "house") - steps_per_beat (int): Time resolution (default: 4, i.e., 16th notes) - swing (float): Swing amount 0.0-1.0 (default: 0.10) - intensity (float): Pattern density 0.0-1.0 (default: 0.9) - seed (int, optional): Random seed for reproducible patterns - fallback_bpm (float, optional): BPM to use if database lookup fails - verbose (bool): Enable verbose logging (default: False)

Returns: - Tuple of (MIDI file object, detected BPM as float)

Raises: - RuntimeError: If BPM lookup fails and no fallback BPM provided

Example:

from beatstoch import generate_from_song

midi_file, bpm = generate_from_song(
    "1979",
    artist="Smashing Pumpkins",
    bars=16,
    style="house",
    swing=0.12,
    verbose=True
)

print(f"Generated {midi_file.length} seconds at {bpm} BPM")
midi_file.save("drums.mid")

generate_stochastic_pattern()

Generate a MIDI drum pattern with explicit BPM (no database lookup).

generate_stochastic_pattern(
    bpm: float,
    bars: int = 4,
    meter: Tuple[int, int] = (4, 4),
    steps_per_beat: int = 4,
    swing: float = 0.12,
    intensity: float = 0.9,
    seed: int = 42,
    style: str = "house",
) -> mido.MidiFile

Parameters: - bpm (float): Target BPM for the pattern - bars (int): Number of bars to generate (default: 4) - meter (Tuple[int, int]): Time signature as (numerator, denominator) (default: (4, 4)) - steps_per_beat (int): Time resolution (default: 4, i.e., 16th notes) - swing (float): Swing amount 0.0-1.0 (default: 0.12) - intensity (float): Pattern density 0.0-1.0 (default: 0.9) - seed (int): Random seed for reproducible patterns (default: 42) - style (str): Drum pattern style - "house", "breaks", or "generic" (default: "house")

Returns: - MIDI file object

Example:

from beatstoch import generate_stochastic_pattern

pattern = generate_stochastic_pattern(
    bpm=128.0,
    bars=8,
    style="breaks",
    swing=0.08,
    intensity=0.85,
    seed=123
)

pattern.save("breakbeat_pattern.mid")

Drum Styles

House

Characteristics: - Four-on-the-floor kick pattern - Steady hi-hat pattern with openings - Snare on beats 2 and 4 - Clean, repetitive structure

Best for: House, techno, minimal techno

Breaks

Characteristics: - Complex kick patterns - Varied snare placement - Syncopated hi-hat patterns - Breakbeat-inspired rhythms

Best for: Breakbeat, drum & bass, hip-hop, experimental

Generic

Characteristics: - Balanced patterns - Moderate complexity - Works across multiple genres - Good starting point for experimentation

Best for: General use, customization, learning

Advanced Usage

Custom Random Seeds

import time

# Use current time for truly random patterns
current_time = int(time.time())
midi_file, bpm = generate_from_song("Song Title", seed=current_time)

# Use song title for consistent patterns per song
song_seed = hash("Song Title - Artist") % (2**31)
midi_file, bpm = generate_from_song("Song Title", artist="Artist", seed=song_seed)

Batch Generation

from beatstoch import generate_stochastic_pattern

# Generate multiple variations
styles = ["house", "breaks", "generic"]
bpms = [120, 125, 130]

for style in styles:
    for bpm in bpms:
        pattern = generate_stochastic_pattern(
            bpm=bpm,
            bars=8,
            style=style,
            seed=42  # Consistent seed for comparison
        )
        pattern.save(f"pattern_{bpm}_{style}.mid")

Integration with DAWs

from beatstoch import generate_from_song

# Generate pattern for current project BPM
def generate_drums_for_project(song_title, artist, project_bpm, bars=8):
    """Generate drums, using project BPM as fallback if lookup fails."""
    try:
        midi_file, detected_bpm = generate_from_song(
            song_title,
            artist=artist,
            bars=bars,
            fallback_bpm=project_bpm
        )
        print(f"Using detected BPM: {detected_bpm}")
        return midi_file, detected_bpm
    except RuntimeError:
        # Fallback to project BPM
        midi_file = generate_stochastic_pattern(project_bpm, bars=bars)
        return midi_file, project_bpm

# Example usage in a DAW automation script
drums, bpm = generate_drums_for_project("My Song", "My Artist", 128)
drums.save("project_drums.mid")

Data Types

MIDI File Object

Returns standard mido.MidiFile objects that can be: - Saved to disk: midi_file.save("filename.mid") - Played with MIDI players - Imported into DAWs - Modified with additional MIDI events

BPM Values

  • Returned as float for precision
  • Typical range: 60-200 BPM
  • Represents the detected or specified tempo

Error Handling

Common Exceptions

from beatstoch import generate_from_song
import requests

try:
    midi_file, bpm = generate_from_song("Song Title", artist="Artist")
except RuntimeError as e:
    print(f"BPM lookup failed: {e}")
    # Use fallback BPM
    fallback_bpm = 120
    midi_file = generate_stochastic_pattern(fallback_bpm, bars=8)
except requests.RequestException as e:
    print(f"Network error: {e}")
    # Handle network issues
except Exception as e:
    print(f"Unexpected error: {e}")

Network Issues

The library makes HTTP requests to BPM databases. Handle network errors:

import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

# Configure retries for network requests
retry_strategy = Retry(
    total=3,
    backoff_factor=1,
    status_forcelist=[429, 500, 502, 503, 504],
)
adapter = HTTPAdapter(max_retries=retry_strategy)
session = requests.Session()
session.mount("http://", adapter)
session.mount("https://", adapter)

Performance Considerations

  • Memory Usage: MIDI files are generated in memory; large patterns may use significant RAM
  • Generation Time: Complex patterns with high steps_per_beat take longer to generate
  • Network Time: BPM lookups add latency (typically 1-3 seconds)
  • File I/O: Saving large MIDI files to disk may take time

Thread Safety

The library is not thread-safe for random number generation when using default seeds. Use explicit seeds for concurrent generation:

import threading
import random

def generate_with_thread_id(bpm, thread_id):
    # Use thread ID in seed for thread-safe generation
    seed = hash((bpm, thread_id)) % (2**31)
    return generate_stochastic_pattern(bpm, seed=seed)

# Safe for concurrent use
threads = []
for i in range(10):
    thread = threading.Thread(target=generate_with_thread_id, args=(128, i))
    threads.append(thread)
    thread.start()

for thread in threads:
    thread.join()