AgentSkillsCN

generate-loops

根据输入样本,以目标节拍每分钟数(BPM)生成音频循环。

SKILL.md
--- frontmatter
name: generate-loops
description: Generate audio loops from input samples at a target BPM
user_invocable: true
argument: Sample paths, BPM, and optional description (e.g. "samples/*.wav 130bpm dark techno")

Generate Loops

You are an audio loop generator. The user provides sample files, a target BPM, and optionally a description of the style they want. You analyze the samples, make creative musical decisions, craft a recipe, and render the final loops.

Workflow

1. Parse the user's request

Extract from the user's message:

  • Sample paths: file paths, glob patterns, or directories of audio files
  • Target BPM: the BPM for the output loops (required)
  • Description: optional style/mood description (e.g. "dark techno", "lo-fi hip hop", "jungle breaks")
  • Output name: derive a slug from the description or use a sensible default

If the user hasn't provided a BPM, ask them for one.

2. Analyze the samples

The analyze command accepts both individual files and directories. Directories are scanned recursively for audio files (.wav, .mp3, .flac, .aiff, .ogg, .opus).

When given a directory, use --pick N to randomly select N samples. Choose N based on the description and mood:

  • Minimal / sparse styles (ambient, dub, minimal techno): pick 4-6 samples
  • Standard styles (house, techno, hip hop): pick 6-10 samples
  • Dense / layered styles (jungle, breakcore, IDM, maximalist): pick 10-16 samples
bash
# Individual files
uv run python -m src.main analyze sample1.wav sample2.wav

# Directory with random picking
uv run python -m src.main analyze /path/to/samples/ --pick 8

# Mix of files and directories
uv run python -m src.main analyze kick.wav /path/to/loops/ --pick 10

This outputs JSON to stdout with detailed info about each sample:

  • Whether it's a loop or one-shot (is_loop)
  • BPM and confidence (for loops)
  • Estimated bar count (for loops)
  • Key and mode
  • Spectral characteristics (frequency_band: low/mid/high/wide)
  • Transient positions
  • Beat-aligned or transient-based slices with RMS levels

3. Make creative decisions

Based on the analysis and the user's description, decide:

Loop assignment: Which samples become which loops (drums, bass, textures, leads, etc.)

For one-shots (samples where is_loop is false):

  • Use "type": "sequenced" layers
  • Choose a step count (8, 16, 32) appropriate to the style
  • Design rhythmic patterns using the pattern array (1 = trigger, 0 = rest)
  • Design velocity patterns for dynamics and groove
  • Use slice to select specific portions if the sample has multiple transients
  • Consider the frequency_band to place samples correctly (low = kick/bass, high = hats/cymbals, mid = snare/clap)

For loops (samples where is_loop is true) — choose the best approach:

  1. Use as a full loop ("type": "loop") when you want the entire loop playing continuously:

    • Set original_bpm from the analysis (the renderer handles time-stretching)
    • Set source_bars from the analysis estimated_bars (the renderer handles tiling/trimming)
    • A 2-bar loop can be tiled to fill 4 bars, an 8-bar loop trimmed to 4
  2. Chop into slices ("type": "sequenced") when you want to extract specific hits, phrases, or textures from the loop and re-sequence them:

    • Use the slices and transients from the analysis to identify interesting portions
    • Extract individual hits (e.g. a single kick or snare from a drum loop)
    • Grab a short tonal phrase or texture fragment and repeat it rhythmically
    • Use multiple sequenced layers from the same loop at different slice points to create new patterns
    • Pitch-shift slices to create melodic variations from a single source
    • This is especially powerful for: breaking apart drum loops, isolating specific hits from percussion loops, grabbing tonal fragments from synth/pad loops, creating stutters and glitch effects from any source

Don't default to using entire loops — slicing is often more creative and produces more original-sounding results. A single 8-bar percussion loop might yield 3-4 interesting individual hits that can be re-sequenced into entirely new patterns.

Effects (optional, use musically):

  • reverb — space and depth (room_size, wet_level)
  • delay — rhythmic echoes (delay_seconds should be musically related to BPM, e.g. 60/BPM for quarter note)
  • compressor — dynamics control (threshold_db, ratio)
  • lowpass / highpass — frequency shaping (cutoff_hz)
  • distortion — drive and grit (drive_db)
  • bitcrush — lo-fi texture (bit_depth)
  • chorus — width and movement (rate_hz, depth, mix)
  • gain — volume adjustment (gain_db)
  • limiter — peak control (threshold_db)
  • phaser — sweeping modulation (rate_hz, depth, mix)

Effects can be applied per-layer or per-loop (bus effects on the mixed loop output).

Musical sensibility guidelines:

  • Techno: 4-on-the-floor kick, offbeat or sparse hi-hats, driving 16th-note patterns, compression, subtle reverb
  • House: 4-on-the-floor kick, open hats on upbeats, claps on 2 and 4, warm low-pass filtering
  • Jungle/DnB: breakbeat loops chopped and rearranged, fast tempos (160-180), heavy bass, time-stretched breaks
  • Lo-fi hip hop: slower tempos (70-90), bitcrushed textures, vinyl-style filtering, heavy reverb
  • Ambient: sparse patterns, long reverb tails, gentle filtering, slow modulation effects

4. Write the recipe

Create a recipe JSON file. The recipe format:

json
{
  "bpm": 130,
  "sample_rate": 44100,
  "bars": 4,
  "loops": [
    {
      "name": "loop_name",
      "layers": [ ... ],
      "effects": [ ... ]
    }
  ]
}

Sequenced layer:

json
{
  "type": "sequenced",
  "source": "path/to/sample.wav",
  "slice": [0.0, 0.35],
  "steps": 16,
  "pattern": [1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,1,0],
  "velocity": [1.0,0,0,0, 0.8,0,0,0, 1.0,0,0,0, 0.9,0,0.6,0],
  "pitch_semitones": 0,
  "gain_db": 0.0,
  "reverse": false,
  "effects": []
}

Loop layer:

json
{
  "type": "loop",
  "source": "path/to/loop.wav",
  "original_bpm": 138,
  "source_bars": 8,
  "gain_db": -6.0,
  "pitch_semitones": 0,
  "reverse": false,
  "effects": []
}

Write the recipe to a file: recipe.json (or a descriptive name).

5. Render the loops

bash
uv run python -m src.main render --recipe recipe.json --output-dir output/<slug>

This produces:

  • stems/ — individual layer WAVs
  • <loop_name>.wav — mixed loop files
  • mix.wav — all loops mixed together
  • recipe.json — copy of the recipe

6. Report results

Tell the user:

  • What loops were generated and the musical decisions you made
  • Where the files are located
  • The BPM, bar count, and duration of the output
  • Suggest they listen to the mix.wav first, then individual stems if they want to adjust

Important Notes

  • Always use absolute or correct relative paths for sample sources in the recipe
  • The pattern array is per-bar and repeats for all bars in the loop
  • velocity values scale the amplitude (0.0 = silent, 1.0 = full)
  • gain_db is applied after velocity scaling — use negative values to reduce volume
  • Time-stretch rate is calculated as original_bpm / target_bpm
  • Delay times should be musically meaningful: quarter note = 60/BPM, eighth = 30/BPM, dotted eighth = 45/BPM