Agent skill

Adaptive Stem Alignment

by HKUDS in HKUDS/OpenSpace

Incremental audio production with duration mismatch handling, adaptive stem extension, and pre-mix alignment verification

MITAuto-check passed

Install Adaptive Stem Alignment

skills CLI
$ npx skills add HKUDS/OpenSpace --skill adaptive-stem-alignment -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install HKUDS/OpenSpace adaptive-stem-alignment --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/HKUDS/OpenSpace.git skills-src && mkdir -p .claude/skills && cp -r skills-src/benchmarks/gdpval/skills/audio-track-production-enhanced-enhanced-b8f537 .claude/skills/adaptive-stem-alignment && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
adaptive-stem-alignment
GitHub stars
7.7k
Token cost
~7.3k tokens
SKILL.md length
614 words
Files
2
Skills in repo
199
Repo updated
First seen
Licence
MIT

At a glance

Incremental audio production with duration mismatch handling, adaptive stem extension, and pre-mix alignment verification

  • Works in 8 steps: Calculate Timing Parameters (Early) → Verify Reference Audio → Generate and Verify Each Stem Individually → …
  • SKILL.md covers Overview, Key Differences from Standard…, Step 1: Calculate Timing… and Step 2: Verify Reference Audio, plus 7 more sections
  • Instructions only: no scripts, shell commands, URLs or credentials in SKILL.md

What it does

Adaptive Stem Alignment is an agent skill from HKUDS/OpenSpace. Incremental audio production with duration mismatch handling, adaptive stem extension, and pre-mix alignment verification

Its SKILL.md is about 7.3k tokens, which your agent loads only when the skill is triggered. The skill folder holds 1 other file.

The repository describes itself as: "OpenSpace: The Skill Management Layer for AI Agents" -- https://open-space.cloud/. The licence is MIT.

Example prompts

  • “/adaptive-stem-alignment”

Requirements

  • Python 3

Workflow steps

8 steps, taken from the step headings in SKILL.md.

  1. Calculate Timing Parameters (Early)
  2. Verify Reference Audio
  3. Generate and Verify Each Stem Individually
  4. Generate Drum Stem Separately
  5. Align Stem Durations (NEW)
  6. Apply Effects with Verification
  7. Export Master Track
  8. Archive and Final Verification

What it can do on your machine

Read from SKILL.md and the folder at commit 3827781. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    No scripts in the folder and no shell commands in SKILL.md (its code samples are python).

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Adaptive Stem Alignment loads about 7.3k tokens when it runs. Until then it costs about 36 tokens; SKILL.md has 614 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~36
When it runs · the whole SKILL.md, loaded when a task matches
~7.3k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from HKUDS/OpenSpace at commit 3827781, republished under its MIT licence (© HKUDS). 614 words, ~7,350 tokens.

Download SKILL.mdSave it as .claude/skills/adaptive-stem-alignment/SKILL.md (or your agent's skills folder). This skill also uses 1 other file; get the full folder from GitHub.
name
adaptive-stem-alignment
description
Incremental audio production with duration mismatch handling, adaptive stem extension, and pre-mix alignment verification

Adaptive Stem Alignment Workflow

This skill provides a resilient pattern for audio production that emphasizes incremental verification, fail-fast principles, and adaptive duration handling. Each major step produces verified outputs before proceeding, with explicit strategies for handling stems of different durations.

Overview

Follow these steps in strict order. Each step must complete successfully and pass verification before proceeding to the next:

  1. Early timing calculation - Derive section transitions from BPM and duration first
  2. Verify reference audio - Validate input file properties and establish target duration
  3. Generate and verify each stem individually - One stem at a time with immediate verification
  4. Generate drum stem separately - Dedicated drum extension with rhythm patterns
  5. Align stem durations - Handle duration mismatches with adaptive extension strategies
  6. Apply effects with verification - Process each stem and verify output
  7. Export master track - Mix all verified stems
  8. Archive and final verification - Package deliverables with comprehensive checks

Key Differences from Standard Workflow

  • Incremental verification: Verify each stem immediately after generation, not just at the end
  • Fail-fast approach: Stop and report errors at each step rather than accumulating failures
  • Early timing: Calculate section transitions before any audio generation
  • Separated drums: Drum stem generation is a distinct step with rhythm-specific processing
  • Memory-efficient: Process stems individually to avoid large array operations that cause sandbox failures
  • Adaptive duration handling: Explicit strategies for mismatched stem durations (zero-padding, looping, crossfade extension)
  • Pre-mix alignment: Verify all stems match target duration before mixing

Step 1: Calculate Timing Parameters (Early)

Calculate all timing parameters before generating any audio. This ensures consistent timing across all stems:

python
def calculate_section_transitions(bpm, total_duration_sec, sections):
    """Calculate beat-aligned transition points for song sections."""
    beats_per_second = bpm / 60.0
    
    section_durations = {}
    cumulative_time = 0
    
    for section_name, beat_count in sections.items():
        duration = beat_count / beats_per_second
        section_durations[section_name] = {
            'start': cumulative_time,
            'end': cumulative_time + duration,
            'beats': beat_count,
            'start_beat': cumulative_time * beats_per_second
        }
        cumulative_time += duration
    
    return section_durations

# Configuration
BPM = 120
DURATION = 137
SECTIONS = {'intro': 16, 'verse': 32, 'chorus': 32, 'bridge': 16, 'outro': 16}

timing = calculate_section_transitions(BPM, DURATION, SECTIONS)
print("Timing calculated:")
for section, data in timing.items():
    print(f"  {section}: {data['start']:.2f}s - {data['end']:.2f}s ({data['beats']} beats)")

Step 2: Verify Reference Audio

Validate the reference file exists and has expected properties:

python
import soundfile as sf
import os

def verify_reference_file(filepath, expected_sample_rate=None, min_duration=None):
    """Verify reference audio file and return info dict."""
    if not os.path.exists(filepath):
        raise FileNotFoundError(f"Reference file not found: {filepath}")
    
    info = sf.info(filepath)
    errors = []
    
    if expected_sample_rate and info.samplerate != expected_sample_rate:
        errors.append(f"Sample rate mismatch: expected {expected_sample_rate}, got {info.samplerate}")
    
    if min_duration and info.duration < min_duration:
        errors.append(f"Duration too short: expected >= {min_duration}s, got {info.duration}s")
    
    if errors:
        raise ValueError(f"Reference file validation failed: {'; '.join(errors)}")
    
    print(f"Reference verified: {info.duration:.2f}s @ {info.samplerate}Hz, {info.channels}ch, {info.subtype}")
    return {
        'sample_rate': info.samplerate,
        'duration': info.duration,
        'channels': info.channels,
        'subtype': info.subtype
    }

# Verify reference
ref_info = verify_reference_file('reference.wav', expected_sample_rate=48000, min_duration=130)
TARGET_DURATION = ref_info['duration']  # Use reference duration as target

Step 3: Generate and Verify Each Stem Individually

Generate one stem at a time, verify it immediately before proceeding to the next:

python
import numpy as np

def generate_stem(name, duration_sec, sample_rate, subtype='FLOAT', section_timing=None):
    """Generate a single stem with explicit sample type."""
    frames = int(duration_sec * sample_rate)
    t = np.linspace(0, duration_sec, frames)
    
    # Generate stem-specific content (customize per stem type)
    if name == 'bass':
        freq = 110  # A2
        audio_data = np.sin(2 * np.pi * freq * t) * 0.8
    elif name == 'guitars':
        freq = 440  # A4
        audio_data = np.sin(2 * np.pi * freq * t) * 0.6
    elif name == 'synths':
        freq = 880  # A5
        audio_data = np.sin(2 * np.pi * freq * t) * 0.5
    elif name == 'bridge':
        freq = 220  # A3
        audio_data = np.sin(2 * np.pi * freq * t) * 0.7
    else:
        audio_data = np.sin(2 * np.pi * 440 * t) * 0.5
    
    # Ensure proper data type
    if subtype == 'FLOAT':
        audio_data = audio_data.astype(np.float32)
    elif subtype == 'PCM_24':
        audio_data = np.clip(audio_data, -1, 1) * (2**23 - 1)
        audio_data = audio_data.astype(np.int32)
    
    filepath = f'{name}_stem.wav'
    sf.write(filepath, audio_data, sample_rate, subtype=subtype, format='WAV')
    
    return filepath, audio_data

def verify_stem(filepath, expected_sample_rate, expected_subtype, expected_duration):
    """Verify a single stem meets specifications."""
    if not os.path.exists(filepath):
        return {'success': False, 'error': f'File not found: {filepath}'}
    
    info = sf.info(filepath)
    errors = []
    
    if info.samplerate != expected_sample_rate:
        errors.append(f'sample_rate: expected {expected_sample_rate}, got {info.samplerate}')
    
    if info.subtype != expected_subtype:
        errors.append(f'subtype: expected {expected_subtype}, got {info.subtype}')
    
    if abs(info.duration - expected_duration) > 1.0:  # Allow 1s tolerance
        errors.append(f'duration: expected ~{expected_duration}s, got {info.duration}s')
    
    if errors:
        return {'success': False, 'error': '; '.join(errors)}
    
    return {'success': True, 'info': info}

# Generate stems one at a time with verification
SAMPLE_RATE = 48000
SUBTYPE = 'FLOAT'
STEM_NAMES = ['bass', 'guitars', 'synths', 'bridge']

generated_stems = []
stem_durations = {}  # Track actual durations for alignment step

for stem_name in STEM_NAMES:
    print(f"\n=== Generating {stem_name} stem ===")
    
    # Generate
    filepath, data = generate_stem(stem_name, DURATION, SAMPLE_RATE, subtype=SUBTYPE)
    
    # Verify immediately
    result = verify_stem(filepath, SAMPLE_RATE, SUBTYPE, DURATION)
    
    if result['success']:
        print(f"✓ {stem_name} stem verified: {result['info'].duration:.2f}s @ {result['info'].samplerate}Hz")
        generated_stems.append(filepath)
        stem_durations[stem_name] = result['info'].duration
    else:
        print(f"✗ {stem_name} stem FAILED: {result['error']}")
        raise RuntimeError(f"Stem generation failed for {stem_name}: {result['error']}")

print(f"\nAll {len(generated_stems)} stems generated and verified successfully")

Step 4: Generate Drum Stem Separately

Drums require different processing (rhythm patterns, percussion sounds):

python
def generate_drum_stem(duration_sec, sample_rate, bpm, section_timing, subtype='FLOAT'):
    """Generate drum stem with rhythm patterns aligned to sections."""
    frames = int(duration_sec * sample_rate)
    audio_data = np.zeros(frames, dtype=np.float32)
    beats_per_second = bpm / 60.0
    
    # Simple kick drum pattern (every beat)
    kick_freq = 60
    kick_duration = 0.1
    kick_frames = int(kick_duration * sample_rate)
    
    for beat_time in np.arange(0, duration_sec, 1.0 / beats_per_second):
        start_frame = int(beat_time * sample_rate)
        end_frame = min(start_frame + kick_frames, frames)
        
        if start_frame < frames:
            t = np.linspace(0, kick_duration, end_frame - start_frame)
            kick = np.exp(-5 * t) * np.sin(2 * np.pi * kick_freq * t)
            audio_data[start_frame:end_frame] += kick * 0.9
    
    # Simple snare pattern (every 2nd and 4th beat)
    snare_freq = 200
    snare_duration = 0.05
    snare_frames = int(snare_duration * sample_rate)
    
    for beat_time in np.arange(0, duration_sec, 2.0 / beats_per_second):
        start_frame = int((beat_time + 0.5 / beats_per_second) * sample_rate)
        end_frame = min(start_frame + snare_frames, frames)
        
        if start_frame < frames:
            t = np.linspace(0, snare_duration, end_frame - start_frame)
            snare = np.exp(-10 * t) * np.random.uniform(-1, 1, len(t)) * 0.5
            audio_data[start_frame:end_frame] += snare * 0.7
    
    audio_data = np.clip(audio_data, -1, 1)
    
    filepath = 'drums_stem.wav'
    sf.write(filepath, audio_data, sample_rate, subtype=subtype, format='WAV')
    
    return filepath, audio_data

print("\n=== Generating drum stem ===")
drums_filepath, drums_data = generate_drum_stem(DURATION, SAMPLE_RATE, BPM, timing, subtype=SUBTYPE)

drums_result = verify_stem(drums_filepath, SAMPLE_RATE, SUBTYPE, DURATION)
if drums_result['success']:
    print(f"✓ Drum stem verified: {drums_result['info'].duration:.2f}s @ {drums_result['info'].samplerate}Hz")
    generated_stems.append(drums_filepath)
    stem_durations['drums'] = drums_result['info'].duration
else:
    print(f"✗ Drum stem FAILED: {drums_result['error']}")
    raise RuntimeError(f"Drum stem generation failed: {drums_result['error']}")

Step 5: Align Stem Durations (NEW)

Handle duration mismatches with adaptive extension strategies. Choose the appropriate method based on stem type:

Show full SKILL.md (284 more words)Show less
Duration Mismatch Handling Strategies
StrategyBest ForHow It WorksConsiderations
Zero-paddingAmbient pads, drones, FXAppend silence to match target durationSimple, no artifacts, but may create abrupt endings
LoopingRhythmic elements, drums, percussionRepeat content to fill durationMaintains rhythm, but requires beat-aligned loop points
Crossfade extensionMelodic elements, vocals, guitarsFade out original, crossfade with looped/faded contentSmoothest transition, but requires careful fade curve design
Time-stretchAny content (when quality matters)Use phase vocoder to stretch without pitch shiftComputationally expensive, may introduce artifacts
python
def align_stem_duration(input_filepath, output_filepath, target_duration, sample_rate, 
                        subtype='FLOAT', strategy='auto', stem_type=None):
    """
    Align stem duration to target using appropriate strategy.
    
    Args:
        input_filepath: Path to input stem
        output_filepath: Path for aligned output
        target_duration: Target duration in seconds
        sample_rate: Sample rate
        subtype: Audio subtype (FLOAT, PCM_24, etc.)
        strategy: 'zero_pad', 'loop', 'crossfade', 'auto'
        stem_type: Type of stem ('rhythmic', 'melodic', 'ambient', 'percussion')
    
    Returns:
        dict with success status and alignment info
    """
    if not os.path.exists(input_filepath):
        return {'success': False, 'error': f'Input file not found: {input_filepath}'}
    
    # Load audio
    data, sr = sf.read(input_filepath)
    current_duration = len(data) / sr
    
    # Check if alignment needed (allow 0.5s tolerance)
    if abs(current_duration - target_duration) < 0.5:
        print(f"  Duration already aligned: {current_duration:.2f}s ≈ {target_duration:.2f}s")
        # Just copy file
        sf.write(output_filepath, data, sample_rate, subtype=subtype, format='WAV')
        return {'success': True, 'strategy': 'none', 'original_duration': current_duration}
    
    # Auto-detect strategy if not specified
    if strategy == 'auto':
        if stem_type in ['rhythmic', 'percussion', 'drums']:
            strategy = 'loop'
        elif stem_type in ['ambient', 'pad', 'drone', 'fx']:
            strategy = 'zero_pad'
        else:  # melodic, vocals, guitars, etc.
            strategy = 'crossfade'
    
    print(f"  Aligning duration: {current_duration:.2f}s → {target_duration:.2f}s using '{strategy}'")
    
    # Calculate frames needed
    target_frames = int(target_duration * sample_rate)
    current_frames = len(data)
    
    if strategy == 'zero_pad':
        # Simple zero-padding
        if current_frames < target_frames:
            aligned_data = np.zeros(target_frames, dtype=data.dtype)
            aligned_data[:current_frames] = data
        else:
            # Truncate with fade-out
            fade_frames = int(0.5 * sample_rate)  # 500ms fade
            aligned_data = data[:target_frames].copy()
            if target_frames < current_frames:
                fade_start = max(0, target_frames - fade_frames)
                fade_curve = np.linspace(1, 0, target_frames - fade_start)
                aligned_data[fade_start:] *= fade_curve
    
    elif strategy == 'loop':
        # Loop to fill duration
        aligned_data = np.zeros(target_frames, dtype=data.dtype)
        loop_count = (target_frames // current_frames) + 1
        
        for i in range(loop_count):
            start = i * current_frames
            end = min(start + current_frames, target_frames)
            copy_len = end - start
            
            if copy_len > 0:
                aligned_data[start:end] = data[:copy_len]
        
        # Apply crossfade at loop points to avoid clicks
        crossfade_frames = int(0.05 * sample_rate)  # 50ms crossfade
        if current_frames > crossfade_frames * 2:
            for i in range(1, loop_count):
                loop_start = i * current_frames
                if loop_start < target_frames:
                    # Crossfade region
                    cf_end = min(loop_start + crossfade_frames, target_frames)
                    cf_start = max(loop_start - crossfade_frames, 0)
                    if cf_end > cf_start:
                        fade_in = np.linspace(0, 1, cf_end - cf_start)
                        fade_out = np.linspace(1, 0, cf_end - cf_start)
                        aligned_data[cf_start:cf_end] = (
                            aligned_data[cf_start:cf_end] * fade_out +
                            np.roll(aligned_data[cf_start:cf_end], -current_frames) * fade_in
                        )
    
    elif strategy == 'crossfade':
        # Crossfade-based extension with smooth transition
        if current_frames < target_frames:
            # Extend with crossfaded loop
            extension_frames = target_frames - current_frames
            fade_frames = min(int(2.0 * sample_rate), extension_frames // 2)  # Max 2s fade
            
            # Create extension from looped content with fade
            extension_data = np.zeros(extension_frames, dtype=data.dtype)
            
            if extension_frames <= current_frames:
                # Just take from beginning with fade-in
                extension_data[:extension_frames] = data[:extension_frames]
                if fade_frames > 0:
                    fade_in = np.linspace(0, 1, min(fade_frames, extension_frames))
                    extension_data[:len(fade_in)] *= fade_in
            else:
                # Loop multiple times with crossfades
                loop_data = np.tile(data, (extension_frames // current_frames) + 2)[:extension_frames]
                
                # Apply fade-in to extension
                if fade_frames > 0:
                    fade_in = np.linspace(0, 1, fade_frames)
                    loop_data[:fade_frames] *= fade_in
                
                extension_data = loop_data
            
            # Concatenate with crossfade
            aligned_data = np.zeros(target_frames, dtype=data.dtype)
            aligned_data[:current_frames] = data
            
            # Crossfade region at junction
            if fade_frames > 0:
                junction_start = current_frames - fade_frames
                junction_end = min(current_frames + fade_frames, target_frames)
                
                if junction_end > junction_start:
                    crossfade_len = junction_end - junction_start
                    fade_out = np.linspace(1, 0, crossfade_len)
                    fade_in = np.linspace(0, 1, crossfade_len)
                    
                    aligned_data[junction_start:junction_end] = (
                        aligned_data[junction_start:junction_end] * fade_out +
                        extension_data[:crossfade_len] * fade_in
                    )
                else:
                    aligned_data[current_frames:current_frames + extension_frames] = extension_data
            else:
                aligned_data[current_frames:] = extension_data
        else:
            # Truncate with fade-out
            fade_frames = int(2.0 * sample_rate)
            aligned_data = data[:target_frames].copy()
            fade_start = max(0, target_frames - fade_frames)
            fade_curve = np.linspace(1, 0, target_frames - fade_start)
            aligned_data[fade_start:] *= fade_curve
    
    else:
        return {'success': False, 'error': f'Unknown strategy: {strategy}'}
    
    # Clip to prevent overload
    aligned_data = np.clip(aligned_data, -1, 1)
    
    # Export
    sf.write(output_filepath, aligned_data, sample_rate, subtype=subtype, format='WAV')
    
    # Verify
    result = verify_stem(output_filepath, sample_rate, subtype, target_duration)
    if result['success']:
        return {
            'success': True,
            'strategy': strategy,
            'original_duration': current_duration,
            'aligned_duration': result['info'].duration
        }
    else:
        return result

# Apply duration alignment to all stems
print("\n=== Aligning stem durations ===")
aligned_stems = []

for stem_name in STEM_NAMES:
    input_file = f'{stem_name}_stem.wav'
    output_file = f'{stem_name}_aligned.wav'
    
    # Determine stem type for strategy selection
    stem_type_map = {
        'bass': 'rhythmic',
        'guitars': 'melodic',
        'synths': 'ambient',
        'bridge': 'melodic'
    }
    stem_type = stem_type_map.get(stem_name, 'melodic')
    
    print(f"Aligning {stem_name} (type: {stem_type})...")
    result = align_stem_duration(
        input_file, output_file, TARGET_DURATION, SAMPLE_RATE,
        subtype=SUBTYPE, strategy='auto', stem_type=stem_type
    )
    
    if result['success']:
        if result['strategy'] != 'none':
            print(f"✓ {stem_name} aligned: {result['original_duration']:.2f}s → {result['aligned_duration']:.2f}s ({result['strategy']})")
        else:
            print(f"✓ {stem_name} already aligned")
        aligned_stems.append(output_file)
    else:
        print(f"✗ {stem_name} alignment FAILED: {result['error']}")
        raise RuntimeError(f"Stem alignment failed for {stem_name}: {result['error']}")

# Align drums separately
drums_aligned = 'drums_aligned.wav'
print(f"Aligning drums (type: percussion)...")
drums_result = align_stem_duration(
    'drums_stem.wav', drums_aligned, TARGET_DURATION, SAMPLE_RATE,
    subtype=SUBTYPE, strategy='auto', stem_type='percussion'
)
if drums_result['success']:
    if drums_result['strategy'] != 'none':
        print(f"✓ Drums aligned: {drums_result['original_duration']:.2f}s → {drums_result['aligned_duration']:.2f}s ({drums_result['strategy']})")
    else:
        print(f"✓ Drums already aligned")
    aligned_stems.append(drums_aligned)
else:
    raise RuntimeError(f"Drums alignment failed: {drums_result['error']}")

# Final duration verification - all stems must match
print("\n=== Verifying duration alignment ===")
final_durations = {}
for stem_file in aligned_stems:
    info = sf.info(stem_file)
    stem_name = os.path.basename(stem_file).replace('_aligned.wav', '')
    final_durations[stem_name] = info.duration
    duration_diff = abs(info.duration - TARGET_DURATION)
    
    if duration_diff > 0.5:
        print(f"✗ WARNING: {stem_name} duration mismatch: {info.duration:.2f}s vs target {TARGET_DURATION:.2f}s")
    else:
        print(f"✓ {stem_name}: {info.duration:.2f}s (Δ{duration_diff:.2f}s)")

max_duration_diff = max(abs(d - TARGET_DURATION) for d in final_durations.values())
if max_duration_diff > 0.5:
    raise RuntimeError(f"Duration alignment incomplete: max deviation {max_duration_diff:.2f}s exceeds tolerance")
print(f"\nAll stems aligned within tolerance (max deviation: {max_duration_diff:.2f}s)")

Step 6: Apply Effects with Verification

Process each stem and verify the output:

python
from scipy import signal

def apply_lowpass_filter(audio_data, sample_rate, cutoff_freq=8000):
    """Apply lowpass filter using scipy.signal."""
    nyquist = sample_rate / 2
    normalized_cutoff = cutoff_freq / nyquist
    b, a = signal.butter(4, normalized_cutoff, btype='low')
    return signal.filtfilt(b, a, audio_data)

def apply_effects_and_verify(input_filepath, output_filepath, sample_rate, subtype):
    """Apply effects to stem and verify output."""
    data, sr = sf.read(input_filepath)
    
    # Apply effects
    processed = apply_lowpass_filter(data, sr, cutoff_freq=8000)
    processed = np.clip(processed, -1, 1)
    
    # Export
    sf.write(output_filepath, processed, sample_rate, subtype=subtype, format='WAV')
    
    # Verify
    result = verify_stem(output_filepath, sample_rate, subtype, TARGET_DURATION)
    return result, processed

print("\n=== Applying effects to all stems ===")
processed_stems = []

for stem_name in STEM_NAMES:
    input_file = f'{stem_name}_aligned.wav'
    output_file = f'{stem_name}_processed.wav'
    
    print(f"Processing {stem_name}...")
    result, _ = apply_effects_and_verify(input_file, output_file, SAMPLE_RATE, SUBTYPE)
    
    if result['success']:
        print(f"✓ {stem_name} processed and verified")
        processed_stems.append(output_file)
    else:
        print(f"✗ {stem_name} processing FAILED: {result['error']}")
        raise RuntimeError(f"Effects processing failed for {stem_name}")

# Process drums separately
drums_output = 'drums_processed.wav'
drums_result, _ = apply_effects_and_verify('drums_aligned.wav', drums_output, SAMPLE_RATE, SUBTYPE)
if drums_result['success']:
    print(f"✓ Drums processed and verified")
    processed_stems.append(drums_output)
else:
    raise RuntimeError(f"Drums processing failed: {drums_result['error']}")

Step 7: Export Master Track

Mix all verified stems into master track:

python
def create_master_track(stem_files, output_filepath, sample_rate, subtype):
    """Create master track from verified stems with gain staging."""
    # Load first stem to get dimensions
    first_data, sr = sf.read(stem_files[0])
    master_audio = np.zeros(len(first_data), dtype=np.float32)
    
    # Verify all stems have matching length
    for stem_file in stem_files:
        data, _ = sf.read(stem_file)
        if len(data) != len(first_data):
            raise ValueError(f"Stem length mismatch: {stem_file} has {len(data)} frames, expected {len(first_data)}")
    
    # Mix all stems with gain staging
    gain_per_stem = 0.4  # Prevent clipping with 5 stems
   
    for i, stem_file in enumerate(stem_files):
        data, sr = sf.read(stem_file)
        master_audio += data * gain_per_stem
        print(f"  Mixed {os.path.basename(stem_file)} (gain: {gain_per_stem})")
    
    # Apply master bus limiting
    master_audio = np.clip(master_audio, -1, 1)
    
    # Soft clip for warmth
    master_audio = np.tanh(master_audio * 1.2) / 1.2
    
    # Export
    sf.write(output_filepath, master_audio, sample_rate, subtype=subtype, format='WAV')
    
    # Verify
    info = sf.info(output_filepath)
    print(f"Master exported: {info.duration:.2f}s @ {info.samplerate}Hz, {info.channels}ch")
    
    return output_filepath, master_audio

print("\n=== Creating master track ===")
master_filepath, master_data = create_master_track(processed_stems, 'master.wav', SAMPLE_RATE, SUBTYPE)

Step 8: Archive and Final Verification

Package deliverables with comprehensive checks:

python
import json
from datetime import datetime

def create_archive_manifest(stem_files, master_file, output_dir='deliverables'):
    """Create archive manifest with comprehensive verification."""
    os.makedirs(output_dir, exist_ok=True)
    
    manifest = {
        'created': datetime.now().isoformat(),
        'target_duration': TARGET_DURATION,
        'sample_rate': SAMPLE_RATE,
        'subtype': SUBTYPE,
        'stems': [],
        'master': None,
        'verification': {
            'all_stems_aligned': True,
            'all_stems_verified': True,
            'master_verified': True
        }
    }
    
    # Verify each stem
    for stem_file in stem_files:
        if not os.path.exists(stem_file):
            manifest['verification']['all_stems_verified'] = False
            continue
        
        info = sf.info(stem_file)
        stem_name = os.path.basename(stem_file)
        duration_diff = abs(info.duration - TARGET_DURATION)
        
        stem_info = {
            'file': stem_name,
            'duration': info.duration,
            'sample_rate': info.samplerate,
            'channels': info.channels,
            'duration_aligned': duration_diff < 0.5
        }
        manifest['stems'].append(stem_info)
        
        if duration_diff >= 0.5:
            manifest['verification']['all_stems_aligned'] = False
            print(f"WARNING: {stem_name} duration misaligned by {duration_diff:.2f}s")
    
    # Verify master
    if os.path.exists(master_file):
        info = sf.info(master_file)
        manifest['master'] = {
            'file': os.path.basename(master_file),
            'duration': info.duration,
            'sample_rate': info.samplerate,
            'channels': info.channels,
            'subtype': info.subtype
        }
        
        # Check master duration matches target
        if abs(info.duration - TARGET_DURATION) > 1.0:
            manifest['verification']['master_verified'] = False
            print(f"WARNING: Master duration {info.duration:.2f}s differs from target {TARGET_DURATION:.2f}s")
    else:
        manifest['verification']['master_verified'] = False
    
    # Save manifest
    manifest_path = os.path.join(output_dir, 'manifest.json')
    with open(manifest_path, 'w') as f:
        json.dump(manifest, f, indent=2)
    
    # Copy files to deliverables
    import shutil
    for stem_file in stem_files:
        shutil.copy(stem_file, output_dir)
    shutil.copy(master_file, output_dir)
    
    return manifest_path, manifest

print("\n=== Creating archive ===")
manifest_path, manifest = create_archive_manifest(processed_stems, master_filepath)
print(f"Archive manifest created: {manifest_path}")

# Final summary
print("\n" + "="*60)
print("PRODUCTION COMPLETE")
print("="*60)
print(f"Target duration: {TARGET_DURATION:.2f}s")
print(f"Sample rate: {SAMPLE_RATE}Hz")
print(f"Stems processed: {len(processed_stems)}")
print(f"All stems aligned: {manifest['verification']['all_stems_aligned']}")
print(f"Master verified: {manifest['verification']['master_verified']}")
print(f"Deliverables: ./deliverables/")
print("="*60)

Troubleshooting Duration Mismatches

Common Causes
  1. Different sample rates: Ensure all stems use the same sample rate
  2. Incorrect frame calculations: Verify frames = int(duration * sample_rate) calculations
  3. Off-by-one errors: Check array indexing and loop boundaries
  4. Resampling artifacts: When converting between sample rates, use high-quality resampling
Strategy Selection Guide

Use zero-padding when:

  • Stem is ambient/pad/drone content
  • Short duration mismatch (< 10% of total)
  • Quick turnaround needed

Use looping when:

  • Stem is rhythmic (drums, percussion, rhythmic bass)
  • Content has clear loop points
  • Loop length divides evenly into target duration

Use crossfade extension when:

  • Stem is melodic (vocals, guitars, synths)
  • Quality is priority over speed
  • Significant duration extension needed

Use time-stretch when:

  • Content cannot be looped or padded
  • Pitch must be preserved
  • High-quality processing is available (e.g., librubberband, elasticsearch)
Verification Checklist
  • All stems have matching sample rate
  • All stems within 0.5s of target duration
  • No clipping in any stem (-1 to 1 range)
  • Master track duration matches target
  • Archive manifest generated with verification status

© HKUDS, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

SKILL.md and 1 other file in benchmarks/gdpval/skills/audio-track-production-enhanced-enhanced-b8f537 of HKUDS/OpenSpace.

  • SKILL.md
  • .skill_id

Open the folder on GitHubat commit 3827781

Compare with similar skills

Adaptive Stem Alignment next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Adaptive Stem Alignment compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Adaptive Stem Alignment this skillHKUDS/OpenSpace7.7k—~7.3kAutomated safety check: PassMIT
Adapter Alignmentevloghq/evlog1.9k—~1.3kAutomated safety check: PassMIT
HyperFrames Audioheygen-com/hyperframes58k1 repos~6.4kAutomated safety check: PassApache-2.0
Ccs Alignthedotmack/claude-mem97k—~6.1kAutomated safety check: PassApache-2.0
Agent Adaptive Coordinatorruvnet/ruflo74k2 repos~4kAutomated safety check: PassMIT
Music Stemsruvnet/ruflo74k—~397Automated safety check: PassMIT

Similar skills

  • Adapter Alignment

    evloghq/evlog

    Twice-monthly check that evlog's drain adapters still send what each provider's own client sends.

    1.9k GitHub stars~1.3k tokensUpdated yesterday
    DevelopmentAuto-check passed
  • HyperFrames Audio

    heygen-com/hyperframes

    Mixes audio already placed in a HyperFrames composition: fades, gain, ducking under a voiceover, effect chains, automation and shared submix buses.

    58k GitHub starsUsed in 1 repo~6.4k tokens
    Media & CreativeAuto-check passed
  • Ccs Align

    thedotmack/claude-mem

    Run the CCS Align seat's hourly breathing cycle — prove the local claude-mem worker is healthy, pull needle observations through search → timeline → getobservations, land them in a seat-owned middle…

    97k GitHub stars~6.1k tokensUpdated yesterday
    Auto-check passed
  • Agent skill for adaptive-coordinator - invoke with $agent-adaptive-coordinator

    74k GitHub starsUsed in 2 repos~4k tokens
    Data & AnalyticsAuto-check passed
  • Music Stems

    ruvnet/ruflo

    Run 4-stem separation (vocals/drums/bass/other) on an existing production

    74k GitHub stars~397 tokensUpdated today
    Auto-check passed
  • Audio Descriptions

    thedaviddias/Front-End-Checklist

    A skill your agent uses when reviewing rendered HTML, interactive components, or design-system patterns related to Provide audio descriptions for video.

    74k GitHub stars~549 tokensUpdated yesterday
    Frontend & DesignAuto-check passed

More from HKUDS/OpenSpace

All 199 skills in this repo
  • Walks through producing a master audio track plus stems in Python, from checking a reference file and timing sections by BPM to effects, a zip archive and final verification.

    7.7k GitHub stars~2.9k tokensUpdated 1 mo ago
    Auto-check passed
  • Handle cascading data retrieval tool failures by falling back to embedded knowledge generation

    7.7k GitHub stars~765 tokensUpdated 1 mo ago
    Auto-check passed
  • Gives an agent a workaround when its code-execution sandbox keeps failing: save the Python script to a file and run it through the shell instead.

    7.7k GitHub stars~588 tokensUpdated 1 mo ago
    Auto-check passed
  • A recovery routine for agents whose sandboxed code runner keeps failing: save the Python script to disk, then run it through the shell and read the output.

    7.7k GitHub stars~652 tokensUpdated 1 mo ago
    Auto-check passed
  • Fallback ladder for failed sandboxed code runs, plus the habit of fixing the working directory first so generated files land in the right place.

    7.7k GitHub stars~1.1k tokensUpdated 1 mo ago
    Auto-check passed
  • Fallback workflow for executing Python code when executecodesandbox fails repeatedly

    7.7k GitHub stars~1.1k tokensUpdated 1 mo ago
    Auto-check passed

Questions about Adaptive Stem Alignment

What does Adaptive Stem Alignment do?

Incremental audio production with duration mismatch handling, adaptive stem extension, and pre-mix alignment verification. Adaptive Stem Alignment is an agent skill from HKUDS/OpenSpace.

How do I install Adaptive Stem Alignment in Claude Code?

Run `npx skills add HKUDS/OpenSpace --skill adaptive-stem-alignment -a claude-code`. Or copy the skill folder (benchmarks/gdpval/skills/audio-track-production-enhanced-enhanced-b8f537 in HKUDS/OpenSpace) into .claude/skills/adaptive-stem-alignment in your project. Claude Code loads it when a task matches its description.

How do I install Adaptive Stem Alignment in Codex?

Run `npx skills add HKUDS/OpenSpace --skill adaptive-stem-alignment -a codex`. Or copy the skill folder (benchmarks/gdpval/skills/audio-track-production-enhanced-enhanced-b8f537 in HKUDS/OpenSpace) into .agents/skills/adaptive-stem-alignment in your project. Codex loads it when a task matches its description.

Can I use Adaptive Stem Alignment in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add HKUDS/OpenSpace --skill adaptive-stem-alignment -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/adaptive-stem-alignment, .gemini/skills/adaptive-stem-alignment, .github/skills/adaptive-stem-alignment and .opencode/skills/adaptive-stem-alignment in your project.

What does Adaptive Stem Alignment need to run?

SKILL.md names no scripts, command-line tools or credentials: Adaptive Stem Alignment is instructions for the agent only. Our summary lists: Python 3.

Does Adaptive Stem Alignment access the network?

SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.

Is Adaptive Stem Alignment safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Adaptive Stem Alignment use?

Adaptive Stem Alignment is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Adaptive Stem Alignment use?

About 7.3k tokens (SKILL.md is roughly 29k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Adaptive Stem Alignment?

Skills that share tags, products or a category with Adaptive Stem Alignment: Adapter Alignment (evloghq/evlog, 1.9k stars), HyperFrames Audio (heygen-com/hyperframes, 58k stars), Ccs Align (thedotmack/claude-mem, 97k stars) and Agent Adaptive Coordinator (ruvnet/ruflo, 74k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Adaptive Stem Alignment?

HKUDS (a GitHub organization) maintains it in HKUDS/OpenSpace, which has 7,743 GitHub stars. The repository holds 199 skills in this directory. The repository was last updated on August 12, 2026.

Source: HKUDS/OpenSpace on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.