# Dependency setup is kept separate from the process supervisor. Nothing is # downloaded or installed when all configured executables already exist. $script:depsProjectRoot = $PSScriptRoot $script:depsManifest = Get-Content -LiteralPath (Join-Path $PSScriptRoot 'dependencies.json') -Raw | ConvertFrom-Json $script:depsDownloadDir = Join-Path $PSScriptRoot '.runtime\downloads' $script:depsInstallDir = Join-Path $PSScriptRoot '.deps' function Test-JackPaths($config) { return (Test-Path -LiteralPath $config.jackd -PathType Leaf) -and (Test-Path -LiteralPath (Join-Path $config.jackTools 'jack_lsp.exe') -PathType Leaf) -and (Test-Path -LiteralPath (Join-Path $config.jackTools 'jack_connect.exe') -PathType Leaf) } function Test-JackRouter { return (Test-Path -LiteralPath 'HKLM:\SOFTWARE\ASIO\JackRouter') -and (Test-Path -LiteralPath 'HKLM:\SOFTWARE\WOW6432Node\ASIO\JackRouter') } function Use-DefaultJackPaths($config) { $candidate = 'C:\Program Files\JACK2' if (-not (Test-Path -LiteralPath (Join-Path $candidate 'jackd.exe'))) { $location = (Get-ItemProperty -Path 'HKLM:\SOFTWARE\JACK' -Name Location -ErrorAction SilentlyContinue).Location if ($location) { $candidate = if ($location -like '*.exe') { Split-Path -Path $location -Parent } else { $location } } } $config.jackd = Join-Path $candidate 'jackd.exe' $config.jackTools = Join-Path $candidate 'tools' } function Get-PinnedDownload($asset) { New-Item -ItemType Directory -Force -Path $script:depsDownloadDir | Out-Null $destination = Join-Path $script:depsDownloadDir $asset.file if (Test-Path -LiteralPath $destination) { $existingHash = (Get-FileHash -LiteralPath $destination -Algorithm SHA256).Hash if ($existingHash -ieq $asset.sha256) { return $destination } Write-Warning "Cached $($asset.file) failed SHA-256 verification; downloading it again." Remove-Item -LiteralPath $destination } $partial = "$destination.partial" Remove-Item -LiteralPath $partial -ErrorAction SilentlyContinue Write-Host "Downloading $($asset.file) from $($asset.url)" try { Invoke-WebRequest -Uri $asset.url -OutFile $partial -UseBasicParsing $actual = (Get-FileHash -LiteralPath $partial -Algorithm SHA256).Hash if ($actual -ine $asset.sha256) { throw "SHA-256 mismatch for $($asset.file): got $actual" } Move-Item -LiteralPath $partial -Destination $destination return $destination } finally { Remove-Item -LiteralPath $partial -ErrorAction SilentlyContinue } } function Assert-DependencyPath([string]$path) { $base = [System.IO.Path]::GetFullPath($script:depsInstallDir).TrimEnd('\') + '\' $target = [System.IO.Path]::GetFullPath($path) if (-not $target.StartsWith($base, [StringComparison]::OrdinalIgnoreCase)) { throw "Refusing to modify directory outside .deps: $target" } return $target } function Remove-DependencyStaging([string]$path) { $target = Assert-DependencyPath $path if (Test-Path -LiteralPath $target) { Remove-Item -LiteralPath $target -Recurse -Force } } function Get-ManagedJackTrip { $folder = Join-Path $script:depsInstallDir "JackTrip-v$($script:depsManifest.jacktrip.version)-Windows-x64" if (-not (Test-Path -LiteralPath $folder)) { return $null } $exe = Get-ChildItem -LiteralPath $folder -Recurse -File -Filter 'jacktrip.exe' | Select-Object -First 1 if ($exe) { return $exe.FullName } return $null } function Install-ManagedJackTrip { $asset = $script:depsManifest.jacktrip $archive = Get-PinnedDownload $asset New-Item -ItemType Directory -Force -Path $script:depsInstallDir | Out-Null $folder = Assert-DependencyPath (Join-Path $script:depsInstallDir "JackTrip-v$($asset.version)-Windows-x64") $staging = Assert-DependencyPath (Join-Path $script:depsInstallDir ('.staging-' + [guid]::NewGuid().ToString('n'))) try { Expand-Archive -LiteralPath $archive -DestinationPath $staging $exe = Get-ChildItem -LiteralPath $staging -Recurse -File -Filter 'jacktrip.exe' | Select-Object -First 1 if (-not $exe) { throw 'Verified JackTrip archive did not contain jacktrip.exe' } if (Test-Path -LiteralPath $folder) { Remove-DependencyStaging $folder } Move-Item -LiteralPath $staging -Destination $folder } finally { Remove-DependencyStaging $staging } return Get-ManagedJackTrip } function Resolve-AudioDependencies($config, [bool]$allowDownload, [bool]$interactive) { if (-not (Test-Path -LiteralPath $config.bridge -PathType Leaf)) { $defaultBridge = 'C:\Program Files (x86)\VB\ASIOBridge\VBCABLE_AsioBridge.exe' if (Test-Path -LiteralPath $defaultBridge -PathType Leaf) { $config.bridge = $defaultBridge } } if (-not (Test-Path -LiteralPath $config.bridge -PathType Leaf)) { Write-Warning 'Hi-Fi Cable / ASIO Bridge is missing. Download and install it as administrator, then reboot Windows.' if ($interactive) { $answer = Read-Host 'Open the official VB-Audio download page now? [y/N]' if ($answer -match '^(y|yes)$') { Start-Process $script:depsManifest.hifiPage } } throw "Hi-Fi Cable installation required: $($script:depsManifest.hifiPage)" } if (-not (Test-JackPaths $config)) { Use-DefaultJackPaths $config } if (-not (Test-JackPaths $config) -or -not (Test-JackRouter)) { if (-not $allowDownload) { throw 'JACK or JACK Router is missing. Run .\audio.ps1 setup in an interactive PowerShell window.' } $installer = Get-PinnedDownload $script:depsManifest.jack if ($interactive) { $answer = Read-Host "JACK or JACK Router is missing. Run its installer ($installer) now? [y/N]" if ($answer -match '^(y|yes)$') { Start-Process -FilePath $installer -Verb RunAs -Wait Use-DefaultJackPaths $config } } if (-not (Test-JackPaths $config) -or -not (Test-JackRouter)) { throw "Install JACK with Full installation (with JACK-Router) from $installer, then run setup again." } } if (-not (Test-Path -LiteralPath $config.jacktrip -PathType Leaf)) { $managed = Get-ManagedJackTrip if (-not $managed) { if (-not $allowDownload) { throw 'JackTrip is missing. Run .\audio.ps1 setup first.' } $managed = Install-ManagedJackTrip } $config.jacktrip = $managed } if (-not (Test-Path -LiteralPath $config.jacktrip -PathType Leaf)) { throw 'JackTrip is still missing after setup.' } return $config }