Files
gh-yebot-rad-cc-plugins-plu…/commands/run-pluginval.md
2025-11-30 09:08:03 +08:00

15 KiB

argument-hint, description, allowed-tools
argument-hint description allowed-tools
[format: vst3|au|aax|all] [strictness: 1-10] Run industry-standard pluginval validation tool on JUCE plugins with comprehensive tests and detailed reports Bash, Read, AskUserQuestion

Run Pluginval Validation

This command runs pluginval, the industry-standard JUCE plugin validation tool, on your built plugins. It automatically detects plugin formats, runs comprehensive tests, and generates detailed validation reports.

Instructions

You are tasked with validating JUCE audio plugins using pluginval. Execute the following steps:

1. Check Pluginval Installation

Verify pluginval is installed and available:

if ! command -v pluginval &> /dev/null; then
    echo "❌ pluginval not found"
    echo ""
    echo "Install pluginval:"
    echo ""
    echo "macOS:"
    echo "  brew install pluginval"
    echo ""
    echo "Or download from:"
    echo "  https://github.com/Tracktion/pluginval/releases"
    echo ""
    echo "After installing, ensure pluginval is in your PATH"
    exit 1
fi

# Verify version
pluginval_version=$(pluginval --version 2>&1 | head -1 || echo "unknown")
echo "✓ pluginval found: $pluginval_version"

2. Detect Built Plugins

Find all built plugin binaries:

echo ""
echo "🔍 Scanning for built plugins..."
echo ""

# Find VST3 plugins
vst3_plugins=$(find build -name "*.vst3" -type d 2>/dev/null)
vst3_count=$(echo "$vst3_plugins" | grep -c ".vst3" || echo "0")

# Find AU plugins (macOS only)
au_plugins=$(find build -name "*.component" -type d 2>/dev/null)
au_count=$(echo "$au_plugins" | grep -c ".component" || echo "0")

# Find AAX plugins
aax_plugins=$(find build -name "*.aaxplugin" -type d 2>/dev/null)
aax_count=$(echo "$aax_plugins" | grep -c ".aaxplugin" || echo "0")

total_plugins=$((vst3_count + au_count + aax_count))

if [ $total_plugins -eq 0 ]; then
    echo "❌ No built plugins found in build/ directory"
    echo ""
    echo "Build your plugin first:"
    echo "  /build-all-formats release"
    echo ""
    exit 1
fi

echo "Found $total_plugins plugin(s):"
[ $vst3_count -gt 0 ] && echo "  - $vst3_count VST3"
[ $au_count -gt 0 ] && echo "  - $au_count AU"
[ $aax_count -gt 0 ] && echo "  - $aax_count AAX"

3. Determine Validation Scope

Use arguments or ask user which formats to validate:

format_arg="${1:-all}"
strictness="${2:-5}"

if [ "$format_arg" != "all" ] && [ "$format_arg" != "vst3" ] && [ "$format_arg" != "au" ] && [ "$format_arg" != "aax" ]; then
    echo "Invalid format: $format_arg"
    echo "Valid options: vst3, au, aax, all"
    exit 1
fi

echo ""
echo "Validation Configuration:"
echo "  Format: $format_arg"
echo "  Strictness: $strictness/10 (higher = more thorough)"
echo ""

4. Configure Pluginval Options

Set up validation parameters based on strictness:

# Base options (always used)
pluginval_opts=(
    "--verbose"
    "--validate-in-process"
    "--output-dir" "build/pluginval-reports"
)

# Strictness-based timeout (higher strictness = longer timeout)
timeout=$((strictness * 30))  # 30 seconds per level
pluginval_opts+=("--timeout-ms" "$((timeout * 1000))")

# Add strictness-specific tests
if [ $strictness -ge 7 ]; then
    # Strict mode - enable all tests
    pluginval_opts+=("--strictness-level" "10")
    pluginval_opts+=("--random-seed" "42")  # Reproducible random tests
elif [ $strictness -ge 4 ]; then
    # Standard mode
    pluginval_opts+=("--strictness-level" "5")
else
    # Quick validation
    pluginval_opts+=("--strictness-level" "1")
    pluginval_opts+=("--skip-gui-tests")  # Skip GUI for speed
fi

# Create output directory
mkdir -p build/pluginval-reports

5. Run Validation on Each Plugin

Execute pluginval for each detected plugin:

echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "Starting Plugin Validation"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""

passed=0
failed=0
skipped=0

validate_plugin() {
    local plugin_path="$1"
    local plugin_name=$(basename "$plugin_path")
    local format_type="$2"

    echo "──────────────────────────────────────────"
    echo "Validating: $plugin_name ($format_type)"
    echo "──────────────────────────────────────────"
    echo ""

    # Check if this format should be validated
    if [ "$format_arg" != "all" ] && [ "$format_arg" != "$format_type" ]; then
        echo "⊘ Skipped (format filter: $format_arg)"
        echo ""
        ((skipped++))
        return
    fi

    # Run pluginval
    local report_file="build/pluginval-reports/${plugin_name%.${format_type}}_${format_type}_report.txt"

    if pluginval "${pluginval_opts[@]}" "$plugin_path" > "$report_file" 2>&1; then
        echo "✅ PASSED - All tests passed"
        ((passed++))
    else
        echo "❌ FAILED - Validation issues detected"
        echo ""
        echo "Top issues:"
        grep -i "error\|fail\|warning" "$report_file" | head -10 || echo "  (see full report)"
        ((failed++))
    fi

    echo ""
    echo "Full report: $report_file"
    echo ""
}

# Validate VST3 plugins
if [ -n "$vst3_plugins" ]; then
    while IFS= read -r plugin; do
        [ -n "$plugin" ] && validate_plugin "$plugin" "vst3"
    done <<< "$vst3_plugins"
fi

# Validate AU plugins
if [ -n "$au_plugins" ]; then
    while IFS= read -r plugin; do
        [ -n "$plugin" ] && validate_plugin "$plugin" "au"
    done <<< "$au_plugins"
fi

# Validate AAX plugins
if [ -n "$aax_plugins" ]; then
    while IFS= read -r plugin; do
        [ -n "$plugin" ] && validate_plugin "$plugin" "aax"
    done <<< "$aax_plugins"
fi

6. Generate Summary Report

Create comprehensive validation summary:

echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "Validation Summary"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""

total_validated=$((passed + failed))
pass_rate=0
if [ $total_validated -gt 0 ]; then
    pass_rate=$(( (passed * 100) / total_validated ))
fi

echo "Results:"
echo "  ✅ Passed:  $passed"
echo "  ❌ Failed:  $failed"
echo "  ⊘  Skipped: $skipped"
echo "  ──────────────"
echo "  Total:     $total_validated validated"
echo ""
echo "Pass Rate:  $pass_rate%"
echo ""

# Create markdown summary report
cat > build/pluginval-reports/SUMMARY.md << EOF
# Pluginval Validation Summary

**Date**: $(date '+%Y-%m-%d %H:%M:%S')
**Strictness**: $strictness/10
**Format Filter**: $format_arg

## Results

| Status | Count |
|--------|-------|
| ✅ Passed | $passed |
| ❌ Failed | $failed |
| ⊘ Skipped | $skipped |
| **Total** | **$total_validated** |

**Pass Rate**: $pass_rate%

## Validated Plugins

### VST3
$(if [ $vst3_count -gt 0 ]; then
    echo "$vst3_plugins" | while read plugin; do
        [ -n "$plugin" ] && echo "- $(basename "$plugin")"
    done
else
    echo "None"
fi)

### Audio Unit (AU)
$(if [ $au_count -gt 0 ]; then
    echo "$au_plugins" | while read plugin; do
        [ -n "$plugin" ] && echo "- $(basename "$plugin")"
    done
else
    echo "None"
fi)

### AAX
$(if [ $aax_count -gt 0 ]; then
    echo "$aax_plugins" | while read plugin; do
        [ -n "$plugin" ] && echo "- $(basename "$plugin")"
    done
else
    echo "None"
fi)

## Pluginval Configuration

\`\`\`
Strictness: $strictness/10
Timeout: ${timeout}s per plugin
Random Seed: 42 (reproducible)
\`\`\`

## Next Steps

$(if [ $failed -gt 0 ]; then
    echo "### Failed Validation"
    echo ""
    echo "Review individual reports in \`build/pluginval-reports/\`"
    echo ""
    echo "Common issues:"
    echo "- Parameter ranges not normalized (0-1)"
    echo "- State save/load not working correctly"
    echo "- Audio glitches at buffer boundaries"
    echo "- Memory leaks or allocations in processBlock"
    echo "- Thread safety violations"
    echo ""
    echo "Get help:"
    echo "\`\`\`"
    echo "@daw-compatibility-engineer review pluginval failures and suggest fixes"
    echo "@technical-lead review plugin architecture for validation issues"
    echo "\`\`\`"
else
    echo "### All Tests Passed! ✅"
    echo ""
    echo "Your plugin(s) passed validation. Next steps:"
    echo ""
    echo "1. Test in real DAWs: Load in Ableton, Logic, Pro Tools, etc."
    echo "2. Run stress tests: \`/stress-test\` (when available)"
    echo "3. Build release: \`/release-build\` (when available)"
fi)

---
Generated by JUCE Dev Team - Pluginval Validation
EOF

echo "📄 Summary report: build/pluginval-reports/SUMMARY.md"
echo ""

7. Display Detailed Failure Analysis

If failures occurred, provide guidance:

if [ $failed -gt 0 ]; then
    echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
    echo "Failure Analysis"
    echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
    echo ""

    echo "Common Pluginval Failures & Fixes:"
    echo ""
    echo "1. Parameter Range Issues"
    echo "   ❌ Parameters not normalized to 0-1"
    echo "   ✅ Fix: Use NormalisableRange and ensure getValue() returns 0-1"
    echo ""
    echo "2. State Save/Load"
    echo "   ❌ getStateInformation/setStateInformation not working"
    echo "   ✅ Fix: Implement proper XML/binary state serialization"
    echo ""
    echo "3. Audio Processing"
    echo "   ❌ Glitches at buffer boundaries or sample rate changes"
    echo "   ✅ Fix: Reset state in prepareToPlay, handle all buffer sizes"
    echo ""
    echo "4. Memory Issues"
    echo "   ❌ Allocations in processBlock"
    echo "   ✅ Fix: Pre-allocate in prepareToPlay, use /juce-best-practices"
    echo ""
    echo "5. Thread Safety"
    echo "   ❌ UI calls from audio thread"
    echo "   ✅ Fix: Use atomics/AsyncUpdater for thread communication"
    echo ""

    echo "Get Expert Help:"
    echo ""
    echo "  @daw-compatibility-engineer analyze pluginval failures"
    echo "  @technical-lead review architecture for validation issues"
    echo "  @plugin-engineer fix state save/load implementation"
    echo ""
fi

8. Set Exit Code

Return appropriate exit code for CI integration:

if [ $failed -eq 0 ]; then
    echo "✅ All validations passed!"
    exit 0
else
    echo "❌ $failed plugin(s) failed validation"
    exit 1
fi

Strictness Levels Explained

Level Duration Tests Use Case
1-3 Quick (1-3 min) Basic Rapid development iteration
4-6 Standard (5-10 min) Comprehensive Pre-commit validation
7-9 Thorough (15-30 min) Extensive Pre-release validation
10 Extreme (30+ min) All + stress Final release validation

Pluginval Tests

Pluginval validates:

  • Parameter System: Range, normalization, automation, smoothing
  • State Management: Save/restore, versioning, backward compatibility
  • Audio Processing: Buffer handling, sample rates, silence, DC offset
  • Threading: Realtime safety, no allocations, no locks
  • MIDI: Note on/off, CC, pitch bend, program changes
  • Latency: Reporting and compensation
  • GUI: Opening, resizing, closing without crashes
  • Preset Management: Loading, saving, initialization

Common Issues & Solutions

Issue: "Plugin failed to load"

Causes:

  • Missing dependencies (JUCE modules, system libraries)
  • Incorrect bundle structure
  • Code signing issues (macOS)

Solutions:

# Check dependencies
otool -L path/to/plugin.vst3/Contents/MacOS/plugin  # macOS
ldd path/to/plugin.so  # Linux

# Verify bundle structure
find path/to/plugin.vst3  # Should match VST3 spec

# Check code signature
codesign -dv --verbose=4 path/to/plugin.vst3  # macOS

Issue: "Parameter range violations"

Fix:

// WRONG
auto param = std::make_unique<AudioParameterFloat>(
    "gain", "Gain", 0.0f, 2.0f, 1.0f);  // Range > 1.0!

// CORRECT
auto param = std::make_unique<AudioParameterFloat>(
    "gain", "Gain",
    NormalisableRange<float>(0.0f, 2.0f),  // Internal range
    1.0f,
    "dB",
    AudioParameterFloat::genericParameter,
    [](float value, int) {
        return String(value * 2.0f, 2) + " dB";  // Display conversion
    }
);

Issue: "State save/load failed"

Fix:

void getStateInformation(MemoryBlock& destData) override {
    auto state = parameters.copyState();
    std::unique_ptr<XmlElement> xml(state.createXml());
    copyXmlToBinary(*xml, destData);
}

void setStateInformation(const void* data, int sizeInBytes) override {
    std::unique_ptr<XmlElement> xml(getXmlFromBinary(data, sizeInBytes));
    if (xml && xml->hasTagName(parameters.state.getType())) {
        parameters.replaceState(ValueTree::fromXml(*xml));
    }
}

Issue: "Audio glitches detected"

Fix:

void prepareToPlay(double sampleRate, int maxBlockSize) override {
    // Reset all DSP state
    dspProcessor.reset();
    dspProcessor.prepare(sampleRate, maxBlockSize);

    // Clear buffers
    tempBuffer.clear();
}

CI/CD Integration

Use in GitHub Actions:

- name: Validate Plugin
  run: /run-pluginval all 5
  continue-on-error: false  # Fail build if validation fails

Platform Notes

macOS

  • AU validation requires macOS
  • Run auval separately for additional AU validation
  • Check Gatekeeper/notarization if plugins won't load

Windows

  • VST3 validation on Windows requires the plugin binary be accessible
  • Check Visual C++ runtime dependencies

Linux

  • VST3 only (AU and AAX not available)
  • Ensure display server running for GUI tests (DISPLAY=:0)

Definition of Done

  • Pluginval installed and accessible
  • All built plugins detected
  • Validation executed for target formats
  • Reports generated in build/pluginval-reports/
  • Summary markdown created
  • Issues flagged with troubleshooting guidance
  • Appropriate exit code returned
  • User provided with next steps

Follow-Up Actions

After validation:

If Passed:

1. Test in real DAWs manually
2. Run @qa-engineer for comprehensive DAW testing
3. Prepare for release: /release-build (when available)

If Failed:

1. Review detailed reports in build/pluginval-reports/
2. Consult @daw-compatibility-engineer for fixes
3. Apply /juce-best-practices for realtime safety
4. Fix issues and re-validate

Advanced Usage

Validate Specific Plugin

pluginval --validate-in-process path/to/MyPlugin.vst3

Custom Strictness

/run-pluginval vst3 10  # Maximum strictness, VST3 only

Skip GUI Tests

Modify pluginval_opts to add:

pluginval_opts+=("--skip-gui-tests")

Reproducible Random Tests

Already included with --random-seed 42 for strictness >= 7.