[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6XBD195WJRAFAPJAXPJBAKD":3,"skill-same:01M6XBD195WJRAFAPJAXPJBAKD":63},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":22,"publishedAt":32,"linkOnly":33,"markdownContent":34,"markdownBody":35,"frontMatter":36,"refName":37,"commitSha":38,"skillDirectory":39,"forksCount":13,"repositoryHtmlUrl":40,"repositoryHomepageUrl":6,"ownerHtmlUrl":41,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":42,"install":43,"resources":56},"01M6XBD195WJRAFAPJAXPJBAKD","adaptive-stem-alignment",null,"Incremental audio production with duration mismatch handling, adaptive stem extension, and pre-mix alignment verification","UF-gzj\u002Fopenspace-claude-evolution","UF-gzj","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F272393507?v=4","01M6XBCZB755P01VVYGQWPYZY3","01M6XBCZFJA5AREA17WGETA3FW",0,"MIT","https:\u002F\u002Fgithub.com\u002FUF-gzj\u002Fopenspace-claude-evolution\u002Fblob\u002Fmain\u002Fgdpval_bench\u002Fskills\u002Faudio-track-production-enhanced-enhanced-b8f537\u002FSKILL.md",[17],{"categoryNo":18,"categoryName":19,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000016","图像与多媒体","SCENARIO","使用场景",[23,24,25,26,27,28,29,30,31],"alignment","adaptive stem alignment","adaptive","verification","Production","Audio","extension","with","mix","2026-11-10 10:12:30",false,"---\nname: adaptive-stem-alignment\ndescription: Incremental audio production with duration mismatch handling, adaptive stem extension, and pre-mix alignment verification\n---\n\n# Adaptive Stem Alignment Workflow\n\nThis 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.\n\n## Overview\n\nFollow these steps in strict order. Each step must complete successfully and pass verification before proceeding to the next:\n\n1. **Early timing calculation** - Derive section transitions from BPM and duration first\n2. **Verify reference audio** - Validate input file properties and establish target duration\n3. **Generate and verify each stem individually** - One stem at a time with immediate verification\n4. **Generate drum stem separately** - Dedicated drum extension with rhythm patterns\n5. **Align stem durations** - Handle duration mismatches with adaptive extension strategies\n6. **Apply effects with verification** - Process each stem and verify output\n7. **Export master track** - Mix all verified stems\n8. **Archive and final verification** - Package deliverables with comprehensive checks\n\n## Key Differences from Standard Workflow\n\n- **Incremental verification**: Verify each stem immediately after generation, not just at the end\n- **Fail-fast approach**: Stop and report errors at each step rather than accumulating failures\n- **Early timing**: Calculate section transitions before any audio generation\n- **Separated drums**: Drum stem generation is a distinct step with rhythm-specific processing\n- **Memory-efficient**: Process stems individually to avoid large array operations that cause sandbox failures\n- **Adaptive duration handling**: Explicit strategies for mismatched stem durations (zero-padding, looping, crossfade extension)\n- **Pre-mix alignment**: Verify all stems match target duration before mixing\n\n## Step 1: Calculate Timing Parameters (Early)\n\nCalculate all timing parameters **before** generating any audio. This ensures consistent timing across all stems:\n\n```python\ndef calculate_section_transitions(bpm, total_duration_sec, sections):\n    \"\"\"Calculate beat-aligned transition points for song sections.\"\"\"\n    beats_per_second = bpm \u002F 60.0\n    \n    section_durations = {}\n    cumulative_time = 0\n    \n    for section_name, beat_count in sections.items():\n        duration = beat_count \u002F beats_per_second\n        section_durations[section_name] = {\n            'start': cumulative_time,\n            'end': cumulative_time + duration,\n            'beats': beat_count,\n            'start_beat': cumulative_time * beats_per_second\n        }\n        cumulative_time += duration\n    \n    return section_durations\n\n# Configuration\nBPM = 120\nDURATION = 137\nSECTIONS = {'intro': 16, 'verse': 32, 'chorus': 32, 'bridge': 16, 'outro': 16}\n\ntiming = calculate_section_transitions(BPM, DURATION, SECTIONS)\nprint(\"Timing calculated:\")\nfor section, data in timing.items():\n    print(f\"  {section}: {data['start']:.2f}s - {data['end']:.2f}s ({data['beats']} beats)\")\n```\n\n## Step 2: Verify Reference Audio\n\nValidate the reference file exists and has expected properties:\n\n```python\nimport soundfile as sf\nimport os\n\ndef verify_reference_file(filepath, expected_sample_rate=None, min_duration=None):\n    \"\"\"Verify reference audio file and return info dict.\"\"\"\n    if not os.path.exists(filepath):\n        raise FileNotFoundError(f\"Reference file not found: {filepath}\")\n    \n    info = sf.info(filepath)\n    errors = []\n    \n    if expected_sample_rate and info.samplerate != expected_sample_rate:\n        errors.append(f\"Sample rate mismatch: expected {expected_sample_rate}, got {info.samplerate}\")\n    \n    if min_duration and info.duration \u003C min_duration:\n        errors.append(f\"Duration too short: expected >= {min_duration}s, got {info.duration}s\")\n    \n    if errors:\n        raise ValueError(f\"Reference file validation failed: {'; '.join(errors)}\")\n    \n    print(f\"Reference verified: {info.duration:.2f}s @ {info.samplerate}Hz, {info.channels}ch, {info.subtype}\")\n    return {\n        'sample_rate': info.samplerate,\n        'duration': info.duration,\n        'channels': info.channels,\n        'subtype': info.subtype\n    }\n\n# Verify reference\nref_info = verify_reference_file('reference.wav', expected_sample_rate=48000, min_duration=130)\nTARGET_DURATION = ref_info['duration']  # Use reference duration as target\n```\n\n## Step 3: Generate and Verify Each Stem Individually\n\nGenerate one stem at a time, verify it immediately before proceeding to the next:\n\n```python\nimport numpy as np\n\ndef generate_stem(name, duration_sec, sample_rate, subtype='FLOAT', section_timing=None):\n    \"\"\"Generate a single stem with explicit sample type.\"\"\"\n    frames = int(duration_sec * sample_rate)\n    t = np.linspace(0, duration_sec, frames)\n    \n    # Generate stem-specific content (customize per stem type)\n    if name == 'bass':\n        freq = 110  # A2\n        audio_data = np.sin(2 * np.pi * freq * t) * 0.8\n    elif name == 'guitars':\n        freq = 440  # A4\n        audio_data = np.sin(2 * np.pi * freq * t) * 0.6\n    elif name == 'synths':\n        freq = 880  # A5\n        audio_data = np.sin(2 * np.pi * freq * t) * 0.5\n    elif name == 'bridge':\n        freq = 220  # A3\n        audio_data = np.sin(2 * np.pi * freq * t) * 0.7\n    else:\n        audio_data = np.sin(2 * np.pi * 440 * t) * 0.5\n    \n    # Ensure proper data type\n    if subtype == 'FLOAT':\n        audio_data = audio_data.astype(np.float32)\n    elif subtype == 'PCM_24':\n        audio_data = np.clip(audio_data, -1, 1) * (2**23 - 1)\n        audio_data = audio_data.astype(np.int32)\n    \n    filepath = f'{name}_stem.wav'\n    sf.write(filepath, audio_data, sample_rate, subtype=subtype, format='WAV')\n    \n    return filepath, audio_data\n\ndef verify_stem(filepath, expected_sample_rate, expected_subtype, expected_duration):\n    \"\"\"Verify a single stem meets specifications.\"\"\"\n    if not os.path.exists(filepath):\n        return {'success': False, 'error': f'File not found: {filepath}'}\n    \n    info = sf.info(filepath)\n    errors = []\n    \n    if info.samplerate != expected_sample_rate:\n        errors.append(f'sample_rate: expected {expected_sample_rate}, got {info.samplerate}')\n    \n    if info.subtype != expected_subtype:\n        errors.append(f'subtype: expected {expected_subtype}, got {info.subtype}')\n    \n    if abs(info.duration - expected_duration) > 1.0:  # Allow 1s tolerance\n        errors.append(f'duration: expected ~{expected_duration}s, got {info.duration}s')\n    \n    if errors:\n        return {'success': False, 'error': '; '.join(errors)}\n    \n    return {'success': True, 'info': info}\n\n# Generate stems one at a time with verification\nSAMPLE_RATE = 48000\nSUBTYPE = 'FLOAT'\nSTEM_NAMES = ['bass', 'guitars', 'synths', 'bridge']\n\ngenerated_stems = []\nstem_durations = {}  # Track actual durations for alignment step\n\nfor stem_name in STEM_NAMES:\n    print(f\"\\n=== Generating {stem_name} stem ===\")\n    \n    # Generate\n    filepath, data = generate_stem(stem_name, DURATION, SAMPLE_RATE, subtype=SUBTYPE)\n    \n    # Verify immediately\n    result = verify_stem(filepath, SAMPLE_RATE, SUBTYPE, DURATION)\n    \n    if result['success']:\n        print(f\"✓ {stem_name} stem verified: {result['info'].duration:.2f}s @ {result['info'].samplerate}Hz\")\n        generated_stems.append(filepath)\n        stem_durations[stem_name] = result['info'].duration\n    else:\n        print(f\"✗ {stem_name} stem FAILED: {result['error']}\")\n        raise RuntimeError(f\"Stem generation failed for {stem_name}: {result['error']}\")\n\nprint(f\"\\nAll {len(generated_stems)} stems generated and verified successfully\")\n```\n\n## Step 4: Generate Drum Stem Separately\n\nDrums require different processing (rhythm patterns, percussion sounds):\n\n```python\ndef generate_drum_stem(duration_sec, sample_rate, bpm, section_timing, subtype='FLOAT'):\n    \"\"\"Generate drum stem with rhythm patterns aligned to sections.\"\"\"\n    frames = int(duration_sec * sample_rate)\n    audio_data = np.zeros(frames, dtype=np.float32)\n    beats_per_second = bpm \u002F 60.0\n    \n    # Simple kick drum pattern (every beat)\n    kick_freq = 60\n    kick_duration = 0.1\n    kick_frames = int(kick_duration * sample_rate)\n    \n    for beat_time in np.arange(0, duration_sec, 1.0 \u002F beats_per_second):\n        start_frame = int(beat_time * sample_rate)\n        end_frame = min(start_frame + kick_frames, frames)\n        \n        if start_frame \u003C frames:\n            t = np.linspace(0, kick_duration, end_frame - start_frame)\n            kick = np.exp(-5 * t) * np.sin(2 * np.pi * kick_freq * t)\n            audio_data[start_frame:end_frame] += kick * 0.9\n    \n    # Simple snare pattern (every 2nd and 4th beat)\n    snare_freq = 200\n    snare_duration = 0.05\n    snare_frames = int(snare_duration * sample_rate)\n    \n    for beat_time in np.arange(0, duration_sec, 2.0 \u002F beats_per_second):\n        start_frame = int((beat_time + 0.5 \u002F beats_per_second) * sample_rate)\n        end_frame = min(start_frame + snare_frames, frames)\n        \n        if start_frame \u003C frames:\n            t = np.linspace(0, snare_duration, end_frame - start_frame)\n            snare = np.exp(-10 * t) * np.random.uniform(-1, 1, len(t)) * 0.5\n            audio_data[start_frame:end_frame] += snare * 0.7\n    \n    audio_data = np.clip(audio_data, -1, 1)\n    \n    filepath = 'drums_stem.wav'\n    sf.write(filepath, audio_data, sample_rate, subtype=subtype, format='WAV')\n    \n    return filepath, audio_data\n\nprint(\"\\n=== Generating drum stem ===\")\ndrums_filepath, drums_data = generate_drum_stem(DURATION, SAMPLE_RATE, BPM, timing, subtype=SUBTYPE)\n\ndrums_result = verify_stem(drums_filepath, SAMPLE_RATE, SUBTYPE, DURATION)\nif drums_result['success']:\n    print(f\"✓ Drum stem verified: {drums_result['info'].duration:.2f}s @ {drums_result['info'].samplerate}Hz\")\n    generated_stems.append(drums_filepath)\n    stem_durations['drums'] = drums_result['info'].duration\nelse:\n    print(f\"✗ Drum stem FAILED: {drums_result['error']}\")\n    raise RuntimeError(f\"Drum stem generation failed: {drums_result['error']}\")\n```\n\n## Step 5: Align Stem Durations (NEW)\n\nHandle duration mismatches with adaptive extension strategies. Choose the appropriate method based on stem type:\n\n### Duration Mismatch Handling Strategies\n\n| Strategy | Best For | How It Works | Considerations |\n|----------|----------|--------------|----------------|\n| **Zero-padding** | Ambient pads, drones, FX | Append silence to match target duration | Simple, no artifacts, but may create abrupt endings |\n| **Looping** | Rhythmic elements, drums, percussion | Repeat content to fill duration | Maintains rhythm, but requires beat-aligned loop points |\n| **Crossfade extension** | Melodic elements, vocals, guitars | Fade out original, crossfade with looped\u002Ffaded content | Smoothest transition, but requires careful fade curve design |\n| **Time-stretch** | Any content (when quality matters) | Use phase vocoder to stretch without pitch shift | Computationally expensive, may introduce artifacts |\n\n```python\ndef align_stem_duration(input_filepath, output_filepath, target_duration, sample_rate, \n                        subtype='FLOAT', strategy='auto', stem_type=None):\n    \"\"\"\n    Align stem duration to target using appropriate strategy.\n    \n    Args:\n        input_filepath: Path to input stem\n        output_filepath: Path for aligned output\n        target_duration: Target duration in seconds\n        sample_rate: Sample rate\n        subtype: Audio subtype (FLOAT, PCM_24, etc.)\n        strategy: 'zero_pad', 'loop', 'crossfade', 'auto'\n        stem_type: Type of stem ('rhythmic', 'melodic', 'ambient', 'percussion')\n    \n    Returns:\n        dict with success status and alignment info\n    \"\"\"\n    if not os.path.exists(input_filepath):\n        return {'success': False, 'error': f'Input file not found: {input_filepath}'}\n    \n    # Load audio\n    data, sr = sf.read(input_filepath)\n    current_duration = len(data) \u002F sr\n    \n    # Check if alignment needed (allow 0.5s tolerance)\n    if abs(current_duration - target_duration) \u003C 0.5:\n        print(f\"  Duration already aligned: {current_duration:.2f}s ≈ {target_duration:.2f}s\")\n        # Just copy file\n        sf.write(output_filepath, data, sample_rate, subtype=subtype, format='WAV')\n        return {'success': True, 'strategy': 'none', 'original_duration': current_duration}\n    \n    # Auto-detect strategy if not specified\n    if strategy == 'auto':\n        if stem_type in ['rhythmic', 'percussion', 'drums']:\n            strategy = 'loop'\n        elif stem_type in ['ambient', 'pad', 'drone', 'fx']:\n            strategy = 'zero_pad'\n        else:  # melodic, vocals, guitars, etc.\n            strategy = 'crossfade'\n    \n    print(f\"  Aligning duration: {current_duration:.2f}s → {target_duration:.2f}s using '{strategy}'\")\n    \n    # Calculate frames needed\n    target_frames = int(target_duration * sample_rate)\n    current_frames = len(data)\n    \n    if strategy == 'zero_pad':\n        # Simple zero-padding\n        if current_frames \u003C target_frames:\n            aligned_data = np.zeros(target_frames, dtype=data.dtype)\n            aligned_data[:current_frames] = data\n        else:\n            # Truncate with fade-out\n            fade_frames = int(0.5 * sample_rate)  # 500ms fade\n            aligned_data = data[:target_frames].copy()\n            if target_frames \u003C current_frames:\n                fade_start = max(0, target_frames - fade_frames)\n                fade_curve = np.linspace(1, 0, target_frames - fade_start)\n                aligned_data[fade_start:] *= fade_curve\n    \n    elif strategy == 'loop':\n        # Loop to fill duration\n        aligned_data = np.zeros(target_frames, dtype=data.dtype)\n        loop_count = (target_frames \u002F\u002F current_frames) + 1\n        \n        for i in range(loop_count):\n            start = i * current_frames\n            end = min(start + current_frames, target_frames)\n            copy_len = end - start\n            \n            if copy_len > 0:\n                aligned_data[start:end] = data[:copy_len]\n        \n        # Apply crossfade at loop points to avoid clicks\n        crossfade_frames = int(0.05 * sample_rate)  # 50ms crossfade\n        if current_frames > crossfade_frames * 2:\n            for i in range(1, loop_count):\n                loop_start = i * current_frames\n                if loop_start \u003C target_frames:\n                    # Crossfade region\n                    cf_end = min(loop_start + crossfade_frames, target_frames)\n                    cf_start = max(loop_start - crossfade_frames, 0)\n                    if cf_end > cf_start:\n                        fade_in = np.linspace(0, 1, cf_end - cf_start)\n                        fade_out = np.linspace(1, 0, cf_end - cf_start)\n                        aligned_data[cf_start:cf_end] = (\n                            aligned_data[cf_start:cf_end] * fade_out +\n                            np.roll(aligned_data[cf_start:cf_end], -current_frames) * fade_in\n                        )\n    \n    elif strategy == 'crossfade':\n        # Crossfade-based extension with smooth transition\n        if current_frames \u003C target_frames:\n            # Extend with crossfaded loop\n            extension_frames = target_frames - current_frames\n            fade_frames = min(int(2.0 * sample_rate), extension_frames \u002F\u002F 2)  # Max 2s fade\n            \n            # Create extension from looped content with fade\n            extension_data = np.zeros(extension_frames, dtype=data.dtype)\n            \n            if extension_frames \u003C= current_frames:\n                # Just take from beginning with fade-in\n                extension_data[:extension_frames] = data[:extension_frames]\n                if fade_frames > 0:\n                    fade_in = np.linspace(0, 1, min(fade_frames, extension_frames))\n                    extension_data[:len(fade_in)] *= fade_in\n            else:\n                # Loop multiple times with crossfades\n                loop_data = np.tile(data, (extension_frames \u002F\u002F current_frames) + 2)[:extension_frames]\n                \n                # Apply fade-in to extension\n                if fade_frames > 0:\n                    fade_in = np.linspace(0, 1, fade_frames)\n                    loop_data[:fade_frames] *= fade_in\n                \n                extension_data = loop_data\n            \n            # Concatenate with crossfade\n            aligned_data = np.zeros(target_frames, dtype=data.dtype)\n            aligned_data[:current_frames] = data\n            \n            # Crossfade region at junction\n            if fade_frames > 0:\n                junction_start = current_frames - fade_frames\n                junction_end = min(current_frames + fade_frames, target_frames)\n                \n                if junction_end > junction_start:\n                    crossfade_len = junction_end - junction_start\n                    fade_out = np.linspace(1, 0, crossfade_len)\n                    fade_in = np.linspace(0, 1, crossfade_len)\n                    \n                    aligned_data[junction_start:junction_end] = (\n                        aligned_data[junction_start:junction_end] * fade_out +\n                        extension_data[:crossfade_len] * fade_in\n                    )\n                else:\n                    aligned_data[current_frames:current_frames + extension_frames] = extension_data\n            else:\n                aligned_data[current_frames:] = extension_data\n        else:\n            # Truncate with fade-out\n            fade_frames = int(2.0 * sample_rate)\n            aligned_data = data[:target_frames].copy()\n            fade_start = max(0, target_frames - fade_frames)\n            fade_curve = np.linspace(1, 0, target_frames - fade_start)\n            aligned_data[fade_start:] *= fade_curve\n    \n    else:\n        return {'success': False, 'error': f'Unknown strategy: {strategy}'}\n    \n    # Clip to prevent overload\n    aligned_data = np.clip(aligned_data, -1, 1)\n    \n    # Export\n    sf.write(output_filepath, aligned_data, sample_rate, subtype=subtype, format='WAV')\n    \n    # Verify\n    result = verify_stem(output_filepath, sample_rate, subtype, target_duration)\n    if result['success']:\n        return {\n            'success': True,\n            'strategy': strategy,\n            'original_duration': current_duration,\n            'aligned_duration': result['info'].duration\n        }\n    else:\n        return result\n\n# Apply duration alignment to all stems\nprint(\"\\n=== Aligning stem durations ===\")\naligned_stems = []\n\nfor stem_name in STEM_NAMES:\n    input_file = f'{stem_name}_stem.wav'\n    output_file = f'{stem_name}_aligned.wav'\n    \n    # Determine stem type for strategy selection\n    stem_type_map = {\n        'bass': 'rhythmic',\n        'guitars': 'melodic',\n        'synths': 'ambient',\n        'bridge': 'melodic'\n    }\n    stem_type = stem_type_map.get(stem_name, 'melodic')\n    \n    print(f\"Aligning {stem_name} (type: {stem_type})...\")\n    result = align_stem_duration(\n        input_file, output_file, TARGET_DURATION, SAMPLE_RATE,\n        subtype=SUBTYPE, strategy='auto', stem_type=stem_type\n    )\n    \n    if result['success']:\n        if result['strategy'] != 'none':\n            print(f\"✓ {stem_name} aligned: {result['original_duration']:.2f}s → {result['aligned_duration']:.2f}s ({result['strategy']})\")\n        else:\n            print(f\"✓ {stem_name} already aligned\")\n        aligned_stems.append(output_file)\n    else:\n        print(f\"✗ {stem_name} alignment FAILED: {result['error']}\")\n        raise RuntimeError(f\"Stem alignment failed for {stem_name}: {result['error']}\")\n\n# Align drums separately\ndrums_aligned = 'drums_aligned.wav'\nprint(f\"Aligning drums (type: percussion)...\")\ndrums_result = align_stem_duration(\n    'drums_stem.wav', drums_aligned, TARGET_DURATION, SAMPLE_RATE,\n    subtype=SUBTYPE, strategy='auto', stem_type='percussion'\n)\nif drums_result['success']:\n    if drums_result['strategy'] != 'none':\n        print(f\"✓ Drums aligned: {drums_result['original_duration']:.2f}s → {drums_result['aligned_duration']:.2f}s ({drums_result['strategy']})\")\n    else:\n        print(f\"✓ Drums already aligned\")\n    aligned_stems.append(drums_aligned)\nelse:\n    raise RuntimeError(f\"Drums alignment failed: {drums_result['error']}\")\n\n# Final duration verification - all stems must match\nprint(\"\\n=== Verifying duration alignment ===\")\nfinal_durations = {}\nfor stem_file in aligned_stems:\n    info = sf.info(stem_file)\n    stem_name = os.path.basename(stem_file).replace('_aligned.wav', '')\n    final_durations[stem_name] = info.duration\n    duration_diff = abs(info.duration - TARGET_DURATION)\n    \n    if duration_diff > 0.5:\n        print(f\"✗ WARNING: {stem_name} duration mismatch: {info.duration:.2f}s vs target {TARGET_DURATION:.2f}s\")\n    else:\n        print(f\"✓ {stem_name}: {info.duration:.2f}s (Δ{duration_diff:.2f}s)\")\n\nmax_duration_diff = max(abs(d - TARGET_DURATION) for d in final_durations.values())\nif max_duration_diff > 0.5:\n    raise RuntimeError(f\"Duration alignment incomplete: max deviation {max_duration_diff:.2f}s exceeds tolerance\")\nprint(f\"\\nAll stems aligned within tolerance (max deviation: {max_duration_diff:.2f}s)\")\n```\n\n## Step 6: Apply Effects with Verification\n\nProcess each stem and verify the output:\n\n```python\nfrom scipy import signal\n\ndef apply_lowpass_filter(audio_data, sample_rate, cutoff_freq=8000):\n    \"\"\"Apply lowpass filter using scipy.signal.\"\"\"\n    nyquist = sample_rate \u002F 2\n    normalized_cutoff = cutoff_freq \u002F nyquist\n    b, a = signal.butter(4, normalized_cutoff, btype='low')\n    return signal.filtfilt(b, a, audio_data)\n\ndef apply_effects_and_verify(input_filepath, output_filepath, sample_rate, subtype):\n    \"\"\"Apply effects to stem and verify output.\"\"\"\n    data, sr = sf.read(input_filepath)\n    \n    # Apply effects\n    processed = apply_lowpass_filter(data, sr, cutoff_freq=8000)\n    processed = np.clip(processed, -1, 1)\n    \n    # Export\n    sf.write(output_filepath, processed, sample_rate, subtype=subtype, format='WAV')\n    \n    # Verify\n    result = verify_stem(output_filepath, sample_rate, subtype, TARGET_DURATION)\n    return result, processed\n\nprint(\"\\n=== Applying effects to all stems ===\")\nprocessed_stems = []\n\nfor stem_name in STEM_NAMES:\n    input_file = f'{stem_name}_aligned.wav'\n    output_file = f'{stem_name}_processed.wav'\n    \n    print(f\"Processing {stem_name}...\")\n    result, _ = apply_effects_and_verify(input_file, output_file, SAMPLE_RATE, SUBTYPE)\n    \n    if result['success']:\n        print(f\"✓ {stem_name} processed and verified\")\n        processed_stems.append(output_file)\n    else:\n        print(f\"✗ {stem_name} processing FAILED: {result['error']}\")\n        raise RuntimeError(f\"Effects processing failed for {stem_name}\")\n\n# Process drums separately\ndrums_output = 'drums_processed.wav'\ndrums_result, _ = apply_effects_and_verify('drums_aligned.wav', drums_output, SAMPLE_RATE, SUBTYPE)\nif drums_result['success']:\n    print(f\"✓ Drums processed and verified\")\n    processed_stems.append(drums_output)\nelse:\n    raise RuntimeError(f\"Drums processing failed: {drums_result['error']}\")\n```\n\n## Step 7: Export Master Track\n\nMix all verified stems into master track:\n\n```python\ndef create_master_track(stem_files, output_filepath, sample_rate, subtype):\n    \"\"\"Create master track from verified stems with gain staging.\"\"\"\n    # Load first stem to get dimensions\n    first_data, sr = sf.read(stem_files[0])\n    master_audio = np.zeros(len(first_data), dtype=np.float32)\n    \n    # Verify all stems have matching length\n    for stem_file in stem_files:\n        data, _ = sf.read(stem_file)\n        if len(data) != len(first_data):\n            raise ValueError(f\"Stem length mismatch: {stem_file} has {len(data)} frames, expected {len(first_data)}\")\n    \n    # Mix all stems with gain staging\n    gain_per_stem = 0.4  # Prevent clipping with 5 stems\n   \n    for i, stem_file in enumerate(stem_files):\n        data, sr = sf.read(stem_file)\n        master_audio += data * gain_per_stem\n        print(f\"  Mixed {os.path.basename(stem_file)} (gain: {gain_per_stem})\")\n    \n    # Apply master bus limiting\n    master_audio = np.clip(master_audio, -1, 1)\n    \n    # Soft clip for warmth\n    master_audio = np.tanh(master_audio * 1.2) \u002F 1.2\n    \n    # Export\n    sf.write(output_filepath, master_audio, sample_rate, subtype=subtype, format='WAV')\n    \n    # Verify\n    info = sf.info(output_filepath)\n    print(f\"Master exported: {info.duration:.2f}s @ {info.samplerate}Hz, {info.channels}ch\")\n    \n    return output_filepath, master_audio\n\nprint(\"\\n=== Creating master track ===\")\nmaster_filepath, master_data = create_master_track(processed_stems, 'master.wav', SAMPLE_RATE, SUBTYPE)\n```\n\n## Step 8: Archive and Final Verification\n\nPackage deliverables with comprehensive checks:\n\n```python\nimport json\nfrom datetime import datetime\n\ndef create_archive_manifest(stem_files, master_file, output_dir='deliverables'):\n    \"\"\"Create archive manifest with comprehensive verification.\"\"\"\n    os.makedirs(output_dir, exist_ok=True)\n    \n    manifest = {\n        'created': datetime.now().isoformat(),\n        'target_duration': TARGET_DURATION,\n        'sample_rate': SAMPLE_RATE,\n        'subtype': SUBTYPE,\n        'stems': [],\n        'master': None,\n        'verification': {\n            'all_stems_aligned': True,\n            'all_stems_verified': True,\n            'master_verified': True\n        }\n    }\n    \n    # Verify each stem\n    for stem_file in stem_files:\n        if not os.path.exists(stem_file):\n            manifest['verification']['all_stems_verified'] = False\n            continue\n        \n        info = sf.info(stem_file)\n        stem_name = os.path.basename(stem_file)\n        duration_diff = abs(info.duration - TARGET_DURATION)\n        \n        stem_info = {\n            'file': stem_name,\n            'duration': info.duration,\n            'sample_rate': info.samplerate,\n            'channels': info.channels,\n            'duration_aligned': duration_diff \u003C 0.5\n        }\n        manifest['stems'].append(stem_info)\n        \n        if duration_diff >= 0.5:\n            manifest['verification']['all_stems_aligned'] = False\n            print(f\"WARNING: {stem_name} duration misaligned by {duration_diff:.2f}s\")\n    \n    # Verify master\n    if os.path.exists(master_file):\n        info = sf.info(master_file)\n        manifest['master'] = {\n            'file': os.path.basename(master_file),\n            'duration': info.duration,\n            'sample_rate': info.samplerate,\n            'channels': info.channels,\n            'subtype': info.subtype\n        }\n        \n        # Check master duration matches target\n        if abs(info.duration - TARGET_DURATION) > 1.0:\n            manifest['verification']['master_verified'] = False\n            print(f\"WARNING: Master duration {info.duration:.2f}s differs from target {TARGET_DURATION:.2f}s\")\n    else:\n        manifest['verification']['master_verified'] = False\n    \n    # Save manifest\n    manifest_path = os.path.join(output_dir, 'manifest.json')\n    with open(manifest_path, 'w') as f:\n        json.dump(manifest, f, indent=2)\n    \n    # Copy files to deliverables\n    import shutil\n    for stem_file in stem_files:\n        shutil.copy(stem_file, output_dir)\n    shutil.copy(master_file, output_dir)\n    \n    return manifest_path, manifest\n\nprint(\"\\n=== Creating archive ===\")\nmanifest_path, manifest = create_archive_manifest(processed_stems, master_filepath)\nprint(f\"Archive manifest created: {manifest_path}\")\n\n# Final summary\nprint(\"\\n\" + \"=\"*60)\nprint(\"PRODUCTION COMPLETE\")\nprint(\"=\"*60)\nprint(f\"Target duration: {TARGET_DURATION:.2f}s\")\nprint(f\"Sample rate: {SAMPLE_RATE}Hz\")\nprint(f\"Stems processed: {len(processed_stems)}\")\nprint(f\"All stems aligned: {manifest['verification']['all_stems_aligned']}\")\nprint(f\"Master verified: {manifest['verification']['master_verified']}\")\nprint(f\"Deliverables: .\u002Fdeliverables\u002F\")\nprint(\"=\"*60)\n```\n\n## Troubleshooting Duration Mismatches\n\n### Common Causes\n1. **Different sample rates**: Ensure all stems use the same sample rate\n2. **Incorrect frame calculations**: Verify `frames = int(duration * sample_rate)` calculations\n3. **Off-by-one errors**: Check array indexing and loop boundaries\n4. **Resampling artifacts**: When converting between sample rates, use high-quality resampling\n\n### Strategy Selection Guide\n\n**Use zero-padding when:**\n- Stem is ambient\u002Fpad\u002Fdrone content\n- Short duration mismatch (\u003C 10% of total)\n- Quick turnaround needed\n\n**Use looping when:**\n- Stem is rhythmic (drums, percussion, rhythmic bass)\n- Content has clear loop points\n- Loop length divides evenly into target duration\n\n**Use crossfade extension when:**\n- Stem is melodic (vocals, guitars, synths)\n- Quality is priority over speed\n- Significant duration extension needed\n\n**Use time-stretch when:**\n- Content cannot be looped or padded\n- Pitch must be preserved\n- High-quality processing is available (e.g., librubberband, elasticsearch)\n\n### Verification Checklist\n- [ ] All stems have matching sample rate\n- [ ] All stems within 0.5s of target duration\n- [ ] No clipping in any stem (-1 to 1 range)\n- [ ] Master track duration matches target\n- [ ] Archive manifest generated with verification status\n","# Adaptive Stem Alignment Workflow\n\nThis 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.\n\n## Overview\n\nFollow these steps in strict order. Each step must complete successfully and pass verification before proceeding to the next:\n\n1. **Early timing calculation** - Derive section transitions from BPM and duration first\n2. **Verify reference audio** - Validate input file properties and establish target duration\n3. **Generate and verify each stem individually** - One stem at a time with immediate verification\n4. **Generate drum stem separately** - Dedicated drum extension with rhythm patterns\n5. **Align stem durations** - Handle duration mismatches with adaptive extension strategies\n6. **Apply effects with verification** - Process each stem and verify output\n7. **Export master track** - Mix all verified stems\n8. **Archive and final verification** - Package deliverables with comprehensive checks\n\n## Key Differences from Standard Workflow\n\n- **Incremental verification**: Verify each stem immediately after generation, not just at the end\n- **Fail-fast approach**: Stop and report errors at each step rather than accumulating failures\n- **Early timing**: Calculate section transitions before any audio generation\n- **Separated drums**: Drum stem generation is a distinct step with rhythm-specific processing\n- **Memory-efficient**: Process stems individually to avoid large array operations that cause sandbox failures\n- **Adaptive duration handling**: Explicit strategies for mismatched stem durations (zero-padding, looping, crossfade extension)\n- **Pre-mix alignment**: Verify all stems match target duration before mixing\n\n## Step 1: Calculate Timing Parameters (Early)\n\nCalculate all timing parameters **before** generating any audio. This ensures consistent timing across all stems:\n\n```python\ndef calculate_section_transitions(bpm, total_duration_sec, sections):\n    \"\"\"Calculate beat-aligned transition points for song sections.\"\"\"\n    beats_per_second = bpm \u002F 60.0\n    \n    section_durations = {}\n    cumulative_time = 0\n    \n    for section_name, beat_count in sections.items():\n        duration = beat_count \u002F beats_per_second\n        section_durations[section_name] = {\n            'start': cumulative_time,\n            'end': cumulative_time + duration,\n            'beats': beat_count,\n            'start_beat': cumulative_time * beats_per_second\n        }\n        cumulative_time += duration\n    \n    return section_durations\n\n# Configuration\nBPM = 120\nDURATION = 137\nSECTIONS = {'intro': 16, 'verse': 32, 'chorus': 32, 'bridge': 16, 'outro': 16}\n\ntiming = calculate_section_transitions(BPM, DURATION, SECTIONS)\nprint(\"Timing calculated:\")\nfor section, data in timing.items():\n    print(f\"  {section}: {data['start']:.2f}s - {data['end']:.2f}s ({data['beats']} beats)\")\n```\n\n## Step 2: Verify Reference Audio\n\nValidate the reference file exists and has expected properties:\n\n```python\nimport soundfile as sf\nimport os\n\ndef verify_reference_file(filepath, expected_sample_rate=None, min_duration=None):\n    \"\"\"Verify reference audio file and return info dict.\"\"\"\n    if not os.path.exists(filepath):\n        raise FileNotFoundError(f\"Reference file not found: {filepath}\")\n    \n    info = sf.info(filepath)\n    errors = []\n    \n    if expected_sample_rate and info.samplerate != expected_sample_rate:\n        errors.append(f\"Sample rate mismatch: expected {expected_sample_rate}, got {info.samplerate}\")\n    \n    if min_duration and info.duration \u003C min_duration:\n        errors.append(f\"Duration too short: expected >= {min_duration}s, got {info.duration}s\")\n    \n    if errors:\n        raise ValueError(f\"Reference file validation failed: {'; '.join(errors)}\")\n    \n    print(f\"Reference verified: {info.duration:.2f}s @ {info.samplerate}Hz, {info.channels}ch, {info.subtype}\")\n    return {\n        'sample_rate': info.samplerate,\n        'duration': info.duration,\n        'channels': info.channels,\n        'subtype': info.subtype\n    }\n\n# Verify reference\nref_info = verify_reference_file('reference.wav', expected_sample_rate=48000, min_duration=130)\nTARGET_DURATION = ref_info['duration']  # Use reference duration as target\n```\n\n## Step 3: Generate and Verify Each Stem Individually\n\nGenerate one stem at a time, verify it immediately before proceeding to the next:\n\n```python\nimport numpy as np\n\ndef generate_stem(name, duration_sec, sample_rate, subtype='FLOAT', section_timing=None):\n    \"\"\"Generate a single stem with explicit sample type.\"\"\"\n    frames = int(duration_sec * sample_rate)\n    t = np.linspace(0, duration_sec, frames)\n    \n    # Generate stem-specific content (customize per stem type)\n    if name == 'bass':\n        freq = 110  # A2\n        audio_data = np.sin(2 * np.pi * freq * t) * 0.8\n    elif name == 'guitars':\n        freq = 440  # A4\n        audio_data = np.sin(2 * np.pi * freq * t) * 0.6\n    elif name == 'synths':\n        freq = 880  # A5\n        audio_data = np.sin(2 * np.pi * freq * t) * 0.5\n    elif name == 'bridge':\n        freq = 220  # A3\n        audio_data = np.sin(2 * np.pi * freq * t) * 0.7\n    else:\n        audio_data = np.sin(2 * np.pi * 440 * t) * 0.5\n    \n    # Ensure proper data type\n    if subtype == 'FLOAT':\n        audio_data = audio_data.astype(np.float32)\n    elif subtype == 'PCM_24':\n        audio_data = np.clip(audio_data, -1, 1) * (2**23 - 1)\n        audio_data = audio_data.astype(np.int32)\n    \n    filepath = f'{name}_stem.wav'\n    sf.write(filepath, audio_data, sample_rate, subtype=subtype, format='WAV')\n    \n    return filepath, audio_data\n\ndef verify_stem(filepath, expected_sample_rate, expected_subtype, expected_duration):\n    \"\"\"Verify a single stem meets specifications.\"\"\"\n    if not os.path.exists(filepath):\n        return {'success': False, 'error': f'File not found: {filepath}'}\n    \n    info = sf.info(filepath)\n    errors = []\n    \n    if info.samplerate != expected_sample_rate:\n        errors.append(f'sample_rate: expected {expected_sample_rate}, got {info.samplerate}')\n    \n    if info.subtype != expected_subtype:\n        errors.append(f'subtype: expected {expected_subtype}, got {info.subtype}')\n    \n    if abs(info.duration - expected_duration) > 1.0:  # Allow 1s tolerance\n        errors.append(f'duration: expected ~{expected_duration}s, got {info.duration}s')\n    \n    if errors:\n        return {'success': False, 'error': '; '.join(errors)}\n    \n    return {'success': True, 'info': info}\n\n# Generate stems one at a time with verification\nSAMPLE_RATE = 48000\nSUBTYPE = 'FLOAT'\nSTEM_NAMES = ['bass', 'guitars', 'synths', 'bridge']\n\ngenerated_stems = []\nstem_durations = {}  # Track actual durations for alignment step\n\nfor stem_name in STEM_NAMES:\n    print(f\"\\n=== Generating {stem_name} stem ===\")\n    \n    # Generate\n    filepath, data = generate_stem(stem_name, DURATION, SAMPLE_RATE, subtype=SUBTYPE)\n    \n    # Verify immediately\n    result = verify_stem(filepath, SAMPLE_RATE, SUBTYPE, DURATION)\n    \n    if result['success']:\n        print(f\"✓ {stem_name} stem verified: {result['info'].duration:.2f}s @ {result['info'].samplerate}Hz\")\n        generated_stems.append(filepath)\n        stem_durations[stem_name] = result['info'].duration\n    else:\n        print(f\"✗ {stem_name} stem FAILED: {result['error']}\")\n        raise RuntimeError(f\"Stem generation failed for {stem_name}: {result['error']}\")\n\nprint(f\"\\nAll {len(generated_stems)} stems generated and verified successfully\")\n```\n\n## Step 4: Generate Drum Stem Separately\n\nDrums require different processing (rhythm patterns, percussion sounds):\n\n```python\ndef generate_drum_stem(duration_sec, sample_rate, bpm, section_timing, subtype='FLOAT'):\n    \"\"\"Generate drum stem with rhythm patterns aligned to sections.\"\"\"\n    frames = int(duration_sec * sample_rate)\n    audio_data = np.zeros(frames, dtype=np.float32)\n    beats_per_second = bpm \u002F 60.0\n    \n    # Simple kick drum pattern (every beat)\n    kick_freq = 60\n    kick_duration = 0.1\n    kick_frames = int(kick_duration * sample_rate)\n    \n    for beat_time in np.arange(0, duration_sec, 1.0 \u002F beats_per_second):\n        start_frame = int(beat_time * sample_rate)\n        end_frame = min(start_frame + kick_frames, frames)\n        \n        if start_frame \u003C frames:\n            t = np.linspace(0, kick_duration, end_frame - start_frame)\n            kick = np.exp(-5 * t) * np.sin(2 * np.pi * kick_freq * t)\n            audio_data[start_frame:end_frame] += kick * 0.9\n    \n    # Simple snare pattern (every 2nd and 4th beat)\n    snare_freq = 200\n    snare_duration = 0.05\n    snare_frames = int(snare_duration * sample_rate)\n    \n    for beat_time in np.arange(0, duration_sec, 2.0 \u002F beats_per_second):\n        start_frame = int((beat_time + 0.5 \u002F beats_per_second) * sample_rate)\n        end_frame = min(start_frame + snare_frames, frames)\n        \n        if start_frame \u003C frames:\n            t = np.linspace(0, snare_duration, end_frame - start_frame)\n            snare = np.exp(-10 * t) * np.random.uniform(-1, 1, len(t)) * 0.5\n            audio_data[start_frame:end_frame] += snare * 0.7\n    \n    audio_data = np.clip(audio_data, -1, 1)\n    \n    filepath = 'drums_stem.wav'\n    sf.write(filepath, audio_data, sample_rate, subtype=subtype, format='WAV')\n    \n    return filepath, audio_data\n\nprint(\"\\n=== Generating drum stem ===\")\ndrums_filepath, drums_data = generate_drum_stem(DURATION, SAMPLE_RATE, BPM, timing, subtype=SUBTYPE)\n\ndrums_result = verify_stem(drums_filepath, SAMPLE_RATE, SUBTYPE, DURATION)\nif drums_result['success']:\n    print(f\"✓ Drum stem verified: {drums_result['info'].duration:.2f}s @ {drums_result['info'].samplerate}Hz\")\n    generated_stems.append(drums_filepath)\n    stem_durations['drums'] = drums_result['info'].duration\nelse:\n    print(f\"✗ Drum stem FAILED: {drums_result['error']}\")\n    raise RuntimeError(f\"Drum stem generation failed: {drums_result['error']}\")\n```\n\n## Step 5: Align Stem Durations (NEW)\n\nHandle duration mismatches with adaptive extension strategies. Choose the appropriate method based on stem type:\n\n### Duration Mismatch Handling Strategies\n\n| Strategy | Best For | How It Works | Considerations |\n|----------|----------|--------------|----------------|\n| **Zero-padding** | Ambient pads, drones, FX | Append silence to match target duration | Simple, no artifacts, but may create abrupt endings |\n| **Looping** | Rhythmic elements, drums, percussion | Repeat content to fill duration | Maintains rhythm, but requires beat-aligned loop points |\n| **Crossfade extension** | Melodic elements, vocals, guitars | Fade out original, crossfade with looped\u002Ffaded content | Smoothest transition, but requires careful fade curve design |\n| **Time-stretch** | Any content (when quality matters) | Use phase vocoder to stretch without pitch shift | Computationally expensive, may introduce artifacts |\n\n```python\ndef align_stem_duration(input_filepath, output_filepath, target_duration, sample_rate, \n                        subtype='FLOAT', strategy='auto', stem_type=None):\n    \"\"\"\n    Align stem duration to target using appropriate strategy.\n    \n    Args:\n        input_filepath: Path to input stem\n        output_filepath: Path for aligned output\n        target_duration: Target duration in seconds\n        sample_rate: Sample rate\n        subtype: Audio subtype (FLOAT, PCM_24, etc.)\n        strategy: 'zero_pad', 'loop', 'crossfade', 'auto'\n        stem_type: Type of stem ('rhythmic', 'melodic', 'ambient', 'percussion')\n    \n    Returns:\n        dict with success status and alignment info\n    \"\"\"\n    if not os.path.exists(input_filepath):\n        return {'success': False, 'error': f'Input file not found: {input_filepath}'}\n    \n    # Load audio\n    data, sr = sf.read(input_filepath)\n    current_duration = len(data) \u002F sr\n    \n    # Check if alignment needed (allow 0.5s tolerance)\n    if abs(current_duration - target_duration) \u003C 0.5:\n        print(f\"  Duration already aligned: {current_duration:.2f}s ≈ {target_duration:.2f}s\")\n        # Just copy file\n        sf.write(output_filepath, data, sample_rate, subtype=subtype, format='WAV')\n        return {'success': True, 'strategy': 'none', 'original_duration': current_duration}\n    \n    # Auto-detect strategy if not specified\n    if strategy == 'auto':\n        if stem_type in ['rhythmic', 'percussion', 'drums']:\n            strategy = 'loop'\n        elif stem_type in ['ambient', 'pad', 'drone', 'fx']:\n            strategy = 'zero_pad'\n        else:  # melodic, vocals, guitars, etc.\n            strategy = 'crossfade'\n    \n    print(f\"  Aligning duration: {current_duration:.2f}s → {target_duration:.2f}s using '{strategy}'\")\n    \n    # Calculate frames needed\n    target_frames = int(target_duration * sample_rate)\n    current_frames = len(data)\n    \n    if strategy == 'zero_pad':\n        # Simple zero-padding\n        if current_frames \u003C target_frames:\n            aligned_data = np.zeros(target_frames, dtype=data.dtype)\n            aligned_data[:current_frames] = data\n        else:\n            # Truncate with fade-out\n            fade_frames = int(0.5 * sample_rate)  # 500ms fade\n            aligned_data = data[:target_frames].copy()\n            if target_frames \u003C current_frames:\n                fade_start = max(0, target_frames - fade_frames)\n                fade_curve = np.linspace(1, 0, target_frames - fade_start)\n                aligned_data[fade_start:] *= fade_curve\n    \n    elif strategy == 'loop':\n        # Loop to fill duration\n        aligned_data = np.zeros(target_frames, dtype=data.dtype)\n        loop_count = (target_frames \u002F\u002F current_frames) + 1\n        \n        for i in range(loop_count):\n            start = i * current_frames\n            end = min(start + current_frames, target_frames)\n            copy_len = end - start\n            \n            if copy_len > 0:\n                aligned_data[start:end] = data[:copy_len]\n        \n        # Apply crossfade at loop points to avoid clicks\n        crossfade_frames = int(0.05 * sample_rate)  # 50ms crossfade\n        if current_frames > crossfade_frames * 2:\n            for i in range(1, loop_count):\n                loop_start = i * current_frames\n                if loop_start \u003C target_frames:\n                    # Crossfade region\n                    cf_end = min(loop_start + crossfade_frames, target_frames)\n                    cf_start = max(loop_start - crossfade_frames, 0)\n                    if cf_end > cf_start:\n                        fade_in = np.linspace(0, 1, cf_end - cf_start)\n                        fade_out = np.linspace(1, 0, cf_end - cf_start)\n                        aligned_data[cf_start:cf_end] = (\n                            aligned_data[cf_start:cf_end] * fade_out +\n                            np.roll(aligned_data[cf_start:cf_end], -current_frames) * fade_in\n                        )\n    \n    elif strategy == 'crossfade':\n        # Crossfade-based extension with smooth transition\n        if current_frames \u003C target_frames:\n            # Extend with crossfaded loop\n            extension_frames = target_frames - current_frames\n            fade_frames = min(int(2.0 * sample_rate), extension_frames \u002F\u002F 2)  # Max 2s fade\n            \n            # Create extension from looped content with fade\n            extension_data = np.zeros(extension_frames, dtype=data.dtype)\n            \n            if extension_frames \u003C= current_frames:\n                # Just take from beginning with fade-in\n                extension_data[:extension_frames] = data[:extension_frames]\n                if fade_frames > 0:\n                    fade_in = np.linspace(0, 1, min(fade_frames, extension_frames))\n                    extension_data[:len(fade_in)] *= fade_in\n            else:\n                # Loop multiple times with crossfades\n                loop_data = np.tile(data, (extension_frames \u002F\u002F current_frames) + 2)[:extension_frames]\n                \n                # Apply fade-in to extension\n                if fade_frames > 0:\n                    fade_in = np.linspace(0, 1, fade_frames)\n                    loop_data[:fade_frames] *= fade_in\n                \n                extension_data = loop_data\n            \n            # Concatenate with crossfade\n            aligned_data = np.zeros(target_frames, dtype=data.dtype)\n            aligned_data[:current_frames] = data\n            \n            # Crossfade region at junction\n            if fade_frames > 0:\n                junction_start = current_frames - fade_frames\n                junction_end = min(current_frames + fade_frames, target_frames)\n                \n                if junction_end > junction_start:\n                    crossfade_len = junction_end - junction_start\n                    fade_out = np.linspace(1, 0, crossfade_len)\n                    fade_in = np.linspace(0, 1, crossfade_len)\n                    \n                    aligned_data[junction_start:junction_end] = (\n                        aligned_data[junction_start:junction_end] * fade_out +\n                        extension_data[:crossfade_len] * fade_in\n                    )\n                else:\n                    aligned_data[current_frames:current_frames + extension_frames] = extension_data\n            else:\n                aligned_data[current_frames:] = extension_data\n        else:\n            # Truncate with fade-out\n            fade_frames = int(2.0 * sample_rate)\n            aligned_data = data[:target_frames].copy()\n            fade_start = max(0, target_frames - fade_frames)\n            fade_curve = np.linspace(1, 0, target_frames - fade_start)\n            aligned_data[fade_start:] *= fade_curve\n    \n    else:\n        return {'success': False, 'error': f'Unknown strategy: {strategy}'}\n    \n    # Clip to prevent overload\n    aligned_data = np.clip(aligned_data, -1, 1)\n    \n    # Export\n    sf.write(output_filepath, aligned_data, sample_rate, subtype=subtype, format='WAV')\n    \n    # Verify\n    result = verify_stem(output_filepath, sample_rate, subtype, target_duration)\n    if result['success']:\n        return {\n            'success': True,\n            'strategy': strategy,\n            'original_duration': current_duration,\n            'aligned_duration': result['info'].duration\n        }\n    else:\n        return result\n\n# Apply duration alignment to all stems\nprint(\"\\n=== Aligning stem durations ===\")\naligned_stems = []\n\nfor stem_name in STEM_NAMES:\n    input_file = f'{stem_name}_stem.wav'\n    output_file = f'{stem_name}_aligned.wav'\n    \n    # Determine stem type for strategy selection\n    stem_type_map = {\n        'bass': 'rhythmic',\n        'guitars': 'melodic',\n        'synths': 'ambient',\n        'bridge': 'melodic'\n    }\n    stem_type = stem_type_map.get(stem_name, 'melodic')\n    \n    print(f\"Aligning {stem_name} (type: {stem_type})...\")\n    result = align_stem_duration(\n        input_file, output_file, TARGET_DURATION, SAMPLE_RATE,\n        subtype=SUBTYPE, strategy='auto', stem_type=stem_type\n    )\n    \n    if result['success']:\n        if result['strategy'] != 'none':\n            print(f\"✓ {stem_name} aligned: {result['original_duration']:.2f}s → {result['aligned_duration']:.2f}s ({result['strategy']})\")\n        else:\n            print(f\"✓ {stem_name} already aligned\")\n        aligned_stems.append(output_file)\n    else:\n        print(f\"✗ {stem_name} alignment FAILED: {result['error']}\")\n        raise RuntimeError(f\"Stem alignment failed for {stem_name}: {result['error']}\")\n\n# Align drums separately\ndrums_aligned = 'drums_aligned.wav'\nprint(f\"Aligning drums (type: percussion)...\")\ndrums_result = align_stem_duration(\n    'drums_stem.wav', drums_aligned, TARGET_DURATION, SAMPLE_RATE,\n    subtype=SUBTYPE, strategy='auto', stem_type='percussion'\n)\nif drums_result['success']:\n    if drums_result['strategy'] != 'none':\n        print(f\"✓ Drums aligned: {drums_result['original_duration']:.2f}s → {drums_result['aligned_duration']:.2f}s ({drums_result['strategy']})\")\n    else:\n        print(f\"✓ Drums already aligned\")\n    aligned_stems.append(drums_aligned)\nelse:\n    raise RuntimeError(f\"Drums alignment failed: {drums_result['error']}\")\n\n# Final duration verification - all stems must match\nprint(\"\\n=== Verifying duration alignment ===\")\nfinal_durations = {}\nfor stem_file in aligned_stems:\n    info = sf.info(stem_file)\n    stem_name = os.path.basename(stem_file).replace('_aligned.wav', '')\n    final_durations[stem_name] = info.duration\n    duration_diff = abs(info.duration - TARGET_DURATION)\n    \n    if duration_diff > 0.5:\n        print(f\"✗ WARNING: {stem_name} duration mismatch: {info.duration:.2f}s vs target {TARGET_DURATION:.2f}s\")\n    else:\n        print(f\"✓ {stem_name}: {info.duration:.2f}s (Δ{duration_diff:.2f}s)\")\n\nmax_duration_diff = max(abs(d - TARGET_DURATION) for d in final_durations.values())\nif max_duration_diff > 0.5:\n    raise RuntimeError(f\"Duration alignment incomplete: max deviation {max_duration_diff:.2f}s exceeds tolerance\")\nprint(f\"\\nAll stems aligned within tolerance (max deviation: {max_duration_diff:.2f}s)\")\n```\n\n## Step 6: Apply Effects with Verification\n\nProcess each stem and verify the output:\n\n```python\nfrom scipy import signal\n\ndef apply_lowpass_filter(audio_data, sample_rate, cutoff_freq=8000):\n    \"\"\"Apply lowpass filter using scipy.signal.\"\"\"\n    nyquist = sample_rate \u002F 2\n    normalized_cutoff = cutoff_freq \u002F nyquist\n    b, a = signal.butter(4, normalized_cutoff, btype='low')\n    return signal.filtfilt(b, a, audio_data)\n\ndef apply_effects_and_verify(input_filepath, output_filepath, sample_rate, subtype):\n    \"\"\"Apply effects to stem and verify output.\"\"\"\n    data, sr = sf.read(input_filepath)\n    \n    # Apply effects\n    processed = apply_lowpass_filter(data, sr, cutoff_freq=8000)\n    processed = np.clip(processed, -1, 1)\n    \n    # Export\n    sf.write(output_filepath, processed, sample_rate, subtype=subtype, format='WAV')\n    \n    # Verify\n    result = verify_stem(output_filepath, sample_rate, subtype, TARGET_DURATION)\n    return result, processed\n\nprint(\"\\n=== Applying effects to all stems ===\")\nprocessed_stems = []\n\nfor stem_name in STEM_NAMES:\n    input_file = f'{stem_name}_aligned.wav'\n    output_file = f'{stem_name}_processed.wav'\n    \n    print(f\"Processing {stem_name}...\")\n    result, _ = apply_effects_and_verify(input_file, output_file, SAMPLE_RATE, SUBTYPE)\n    \n    if result['success']:\n        print(f\"✓ {stem_name} processed and verified\")\n        processed_stems.append(output_file)\n    else:\n        print(f\"✗ {stem_name} processing FAILED: {result['error']}\")\n        raise RuntimeError(f\"Effects processing failed for {stem_name}\")\n\n# Process drums separately\ndrums_output = 'drums_processed.wav'\ndrums_result, _ = apply_effects_and_verify('drums_aligned.wav', drums_output, SAMPLE_RATE, SUBTYPE)\nif drums_result['success']:\n    print(f\"✓ Drums processed and verified\")\n    processed_stems.append(drums_output)\nelse:\n    raise RuntimeError(f\"Drums processing failed: {drums_result['error']}\")\n```\n\n## Step 7: Export Master Track\n\nMix all verified stems into master track:\n\n```python\ndef create_master_track(stem_files, output_filepath, sample_rate, subtype):\n    \"\"\"Create master track from verified stems with gain staging.\"\"\"\n    # Load first stem to get dimensions\n    first_data, sr = sf.read(stem_files[0])\n    master_audio = np.zeros(len(first_data), dtype=np.float32)\n    \n    # Verify all stems have matching length\n    for stem_file in stem_files:\n        data, _ = sf.read(stem_file)\n        if len(data) != len(first_data):\n            raise ValueError(f\"Stem length mismatch: {stem_file} has {len(data)} frames, expected {len(first_data)}\")\n    \n    # Mix all stems with gain staging\n    gain_per_stem = 0.4  # Prevent clipping with 5 stems\n   \n    for i, stem_file in enumerate(stem_files):\n        data, sr = sf.read(stem_file)\n        master_audio += data * gain_per_stem\n        print(f\"  Mixed {os.path.basename(stem_file)} (gain: {gain_per_stem})\")\n    \n    # Apply master bus limiting\n    master_audio = np.clip(master_audio, -1, 1)\n    \n    # Soft clip for warmth\n    master_audio = np.tanh(master_audio * 1.2) \u002F 1.2\n    \n    # Export\n    sf.write(output_filepath, master_audio, sample_rate, subtype=subtype, format='WAV')\n    \n    # Verify\n    info = sf.info(output_filepath)\n    print(f\"Master exported: {info.duration:.2f}s @ {info.samplerate}Hz, {info.channels}ch\")\n    \n    return output_filepath, master_audio\n\nprint(\"\\n=== Creating master track ===\")\nmaster_filepath, master_data = create_master_track(processed_stems, 'master.wav', SAMPLE_RATE, SUBTYPE)\n```\n\n## Step 8: Archive and Final Verification\n\nPackage deliverables with comprehensive checks:\n\n```python\nimport json\nfrom datetime import datetime\n\ndef create_archive_manifest(stem_files, master_file, output_dir='deliverables'):\n    \"\"\"Create archive manifest with comprehensive verification.\"\"\"\n    os.makedirs(output_dir, exist_ok=True)\n    \n    manifest = {\n        'created': datetime.now().isoformat(),\n        'target_duration': TARGET_DURATION,\n        'sample_rate': SAMPLE_RATE,\n        'subtype': SUBTYPE,\n        'stems': [],\n        'master': None,\n        'verification': {\n            'all_stems_aligned': True,\n            'all_stems_verified': True,\n            'master_verified': True\n        }\n    }\n    \n    # Verify each stem\n    for stem_file in stem_files:\n        if not os.path.exists(stem_file):\n            manifest['verification']['all_stems_verified'] = False\n            continue\n        \n        info = sf.info(stem_file)\n        stem_name = os.path.basename(stem_file)\n        duration_diff = abs(info.duration - TARGET_DURATION)\n        \n        stem_info = {\n            'file': stem_name,\n            'duration': info.duration,\n            'sample_rate': info.samplerate,\n            'channels': info.channels,\n            'duration_aligned': duration_diff \u003C 0.5\n        }\n        manifest['stems'].append(stem_info)\n        \n        if duration_diff >= 0.5:\n            manifest['verification']['all_stems_aligned'] = False\n            print(f\"WARNING: {stem_name} duration misaligned by {duration_diff:.2f}s\")\n    \n    # Verify master\n    if os.path.exists(master_file):\n        info = sf.info(master_file)\n        manifest['master'] = {\n            'file': os.path.basename(master_file),\n            'duration': info.duration,\n            'sample_rate': info.samplerate,\n            'channels': info.channels,\n            'subtype': info.subtype\n        }\n        \n        # Check master duration matches target\n        if abs(info.duration - TARGET_DURATION) > 1.0:\n            manifest['verification']['master_verified'] = False\n            print(f\"WARNING: Master duration {info.duration:.2f}s differs from target {TARGET_DURATION:.2f}s\")\n    else:\n        manifest['verification']['master_verified'] = False\n    \n    # Save manifest\n    manifest_path = os.path.join(output_dir, 'manifest.json')\n    with open(manifest_path, 'w') as f:\n        json.dump(manifest, f, indent=2)\n    \n    # Copy files to deliverables\n    import shutil\n    for stem_file in stem_files:\n        shutil.copy(stem_file, output_dir)\n    shutil.copy(master_file, output_dir)\n    \n    return manifest_path, manifest\n\nprint(\"\\n=== Creating archive ===\")\nmanifest_path, manifest = create_archive_manifest(processed_stems, master_filepath)\nprint(f\"Archive manifest created: {manifest_path}\")\n\n# Final summary\nprint(\"\\n\" + \"=\"*60)\nprint(\"PRODUCTION COMPLETE\")\nprint(\"=\"*60)\nprint(f\"Target duration: {TARGET_DURATION:.2f}s\")\nprint(f\"Sample rate: {SAMPLE_RATE}Hz\")\nprint(f\"Stems processed: {len(processed_stems)}\")\nprint(f\"All stems aligned: {manifest['verification']['all_stems_aligned']}\")\nprint(f\"Master verified: {manifest['verification']['master_verified']}\")\nprint(f\"Deliverables: .\u002Fdeliverables\u002F\")\nprint(\"=\"*60)\n```\n\n## Troubleshooting Duration Mismatches\n\n### Common Causes\n1. **Different sample rates**: Ensure all stems use the same sample rate\n2. **Incorrect frame calculations**: Verify `frames = int(duration * sample_rate)` calculations\n3. **Off-by-one errors**: Check array indexing and loop boundaries\n4. **Resampling artifacts**: When converting between sample rates, use high-quality resampling\n\n### Strategy Selection Guide\n\n**Use zero-padding when:**\n- Stem is ambient\u002Fpad\u002Fdrone content\n- Short duration mismatch (\u003C 10% of total)\n- Quick turnaround needed\n\n**Use looping when:**\n- Stem is rhythmic (drums, percussion, rhythmic bass)\n- Content has clear loop points\n- Loop length divides evenly into target duration\n\n**Use crossfade extension when:**\n- Stem is melodic (vocals, guitars, synths)\n- Quality is priority over speed\n- Significant duration extension needed\n\n**Use time-stretch when:**\n- Content cannot be looped or padded\n- Pitch must be preserved\n- High-quality processing is available (e.g., librubberband, elasticsearch)\n\n### Verification Checklist\n- [ ] All stems have matching sample rate\n- [ ] All stems within 0.5s of target duration\n- [ ] No clipping in any stem (-1 to 1 range)\n- [ ] Master track duration matches target\n- [ ] Archive manifest generated with verification status\n",{"name":5,"description":7},"main","0650921d63895de3997bc81f1ff1d0ac67032072","gdpval_bench\u002Fskills\u002Faudio-track-production-enhanced-enhanced-b8f537","https:\u002F\u002Fgithub.com\u002FUF-gzj\u002Fopenspace-claude-evolution","https:\u002F\u002Fgithub.com\u002FUF-gzj","2026-04-16 09:31:03",{"source":8,"skillName":5,"commands":44,"prompt":54,"zipAvailable":55},[45,48,51],{"tool":46,"command":47},"npx","npx skills add UF-gzj\u002Fopenspace-claude-evolution --skill adaptive-stem-alignment",{"tool":49,"command":50},"bunx","bunx skills add UF-gzj\u002Fopenspace-claude-evolution --skill adaptive-stem-alignment",{"tool":52,"command":53},"pnpm","pnpm dlx skills add UF-gzj\u002Fopenspace-claude-evolution --skill adaptive-stem-alignment","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FUF-gzj\u002Fopenspace-claude-evolution\u002Fblob\u002Fmain\u002Fgdpval_bench\u002Fskills\u002Faudio-track-production-enhanced-enhanced-b8f537\u002FSKILL.md",true,[57],{"path":58,"resourceType":59,"resourceTypeDesc":60,"sizeBytes":61,"sourceHtmlUrl":62},".skill_id","OTHER","其他",61,"https:\u002F\u002Fgithub.com\u002FUF-gzj\u002Fopenspace-claude-evolution\u002Fblob\u002Fmain\u002Fgdpval_bench\u002Fskills\u002Faudio-track-production-enhanced-enhanced-b8f537\u002F.skill_id",[64,89,104,113,143,159],{"skillNo":65,"name":66,"nameZh":6,"description":67,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":68,"categories":69,"keywords":70,"publishedAt":32},"01M6XCCXD3NCM2YKR3WNGBASPC","write-special-chars-ts-check","Workaround for write_file failures caused by special characters (apostrophes, backticks, template literals) using a Python heredoc script, plus a reliable TypeScript type-checking step that filters output to only the newly-written files to avoid being misled by pre-existing errors.","https:\u002F\u002Fgithub.com\u002FUF-gzj\u002Fopenspace-claude-evolution\u002Fblob\u002Fmain\u002Fshowcase\u002Fskills\u002Fwrite-special-chars-ts-check\u002FSKILL.md",[],[71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88],"check","write","write special chars ts check","typescript","filters","characters","Existing","type-checking","for","errors","script","output","type","files","only","template","file","python",{"skillNo":90,"name":91,"nameZh":6,"description":92,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":93,"categories":94,"keywords":95,"publishedAt":32},"01M6XCCT7E3J922Q345PBGSHPN","write-special-chars-readback","Workaround for write_file failures caused by special characters (apostrophes, backticks, template literals) using a Python heredoc script, with mandatory post-write verification via read_file and cleanup of \u002Ftmp helper scripts.","https:\u002F\u002Fgithub.com\u002FUF-gzj\u002Fopenspace-claude-evolution\u002Fblob\u002Fmain\u002Fshowcase\u002Fskills\u002Fwrite-special-chars-readback\u002FSKILL.md",[],[96,97,72,87,98,88,99,100,101,102,103,86,26,30,76,79,81],"readback","write special chars readback","helper","post","via","scripts","cleanup","read",{"skillNo":105,"name":106,"nameZh":6,"description":107,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":108,"categories":109,"keywords":110,"publishedAt":32},"01M6XCCMQX1R8B6FECWB3P63T7","write-special-chars-heredoc","Workaround for write_file failures caused by special characters (apostrophes, backticks, template literals) by using a Python heredoc script executed via shell.","https:\u002F\u002Fgithub.com\u002FUF-gzj\u002Fopenspace-claude-evolution\u002Fblob\u002Fmain\u002Fshowcase\u002Fskills\u002Fwrite-special-chars-heredoc\u002FSKILL.md",[],[111,72,76,112,81,100,86,87,88,79],"write special chars heredoc","shell",{"skillNo":114,"name":115,"nameZh":6,"description":116,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":117,"categories":118,"keywords":124,"publishedAt":32},"01M6XCCG41M994JJEX6VN52PEP","worldmonitor-reference","Curated architecture index of the WorldMonitor open-source dashboard. Reference for extracting patterns — vanilla TypeScript, Panel class hierarchy, service layer, CSS grid, API edge functions, refresh scheduler, and 60+ data source integrations.","https:\u002F\u002Fgithub.com\u002FUF-gzj\u002Fopenspace-claude-evolution\u002Fblob\u002Fmain\u002Fshowcase\u002Fskills\u002Fworldmonitor-reference\u002FSKILL.md",[119],{"categoryNo":120,"categoryName":121,"taxonomyType":122,"taxonomyTypeDesc":123},"01JBSEEDCAT000000000000033","数据分析师","PROFESSION","适用职业",[125,126,127,128,129,74,130,131,132,133,134,79,135,136,137,138,139,140,141,142],"reference","worldmonitor","worldmonitor reference","architecture","dashboard","css","scheduler","layer","hierarchy","source","extracting","panel","patterns","edge functions","integrations","open","api","data",{"skillNo":144,"name":145,"nameZh":6,"description":146,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":147,"categories":148,"keywords":149,"publishedAt":32},"01M6XCCCHWNKG2W4VH9E6A10HF","virtual-list","Implement efficient virtual scrolling for rendering large lists with DOM recycling, chunk-based rendering, and performance optimizations","https:\u002F\u002Fgithub.com\u002FUF-gzj\u002Fopenspace-claude-evolution\u002Fblob\u002Fmain\u002Fshowcase\u002Fskills\u002Fvirtual-list\u002FSKILL.md",[],[150,151,152,153,79,154,30,155,156,157,158],"virtual list","list","virtual","chunk","dom","rendering","recycling","implement","performance",{"skillNo":160,"name":161,"nameZh":6,"description":162,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":163,"categories":164,"keywords":165,"publishedAt":32},"01M6XCC7X8PKMR2DEW91XGHYSV","verify-directory-structure","Diagnose and resolve file access issues by first verifying the directory structure.","https:\u002F\u002Fgithub.com\u002FUF-gzj\u002Fopenspace-claude-evolution\u002Fblob\u002Fmain\u002Fshowcase\u002Fskills\u002Fverify-directory-structure\u002FSKILL.md",[],[166,167,168,169,170,171,87,172,173,174],"directory","verify directory structure","structure","verify","access","first","issues","diagnose","file access"]