Skip to content

Instantly share code, notes, and snippets.

@shyamzzp
Last active July 30, 2026 08:51
Show Gist options
  • Select an option

  • Save shyamzzp/98c0e820a3e82c27b64a1c53aa027b41 to your computer and use it in GitHub Desktop.

Select an option

Save shyamzzp/98c0e820a3e82c27b64a1c53aa027b41 to your computer and use it in GitHub Desktop.
Install local live Zoom/system-audio transcription on macOS, Linux, or Windows
# Installs local live Windows system-audio transcription with whisper.cpp.
[CmdletBinding()]
param(
[switch]$VerifyOnly
)
$ErrorActionPreference = 'Stop'
$RepoUrl = 'https://github.com/ggml-org/whisper.cpp.git'
$WhisperDirectory = if ($env:WHISPER_DIRECTORY) { $env:WHISPER_DIRECTORY } else { Join-Path $HOME 'whisper.cpp' }
$ModelPath = Join-Path $WhisperDirectory 'models\ggml-base.en.bin'
$VcpkgDirectory = if ($env:VCPKG_ROOT) { $env:VCPKG_ROOT } else { Join-Path $HOME 'vcpkg' }
function Stop-Install([string]$Message) {
throw "Error: $Message"
}
function Write-Section([string]$Message) {
Write-Host "`n==> $Message" -ForegroundColor Cyan
}
function Assert-Windows {
if ([System.Environment]::OSVersion.Platform -ne [System.PlatformID]::Win32NT) {
Stop-Install 'This installer requires Windows.'
}
}
function Add-CommonToolPaths {
$paths = @('C:\Program Files\CMake\bin', 'C:\Program Files\Git\cmd')
foreach ($path in $paths) {
if ((Test-Path $path) -and -not (($env:Path -split ';') -contains $path)) {
$env:Path = "$env:Path;$path"
}
}
}
function Install-WinGetPackage([string]$Id, [string[]]$Arguments = @()) {
& winget install --id $Id --exact --accept-package-agreements --accept-source-agreements @Arguments
if ($LASTEXITCODE -ne 0) { Stop-Install "WinGet failed to install $Id." }
}
function Install-Dependencies {
Get-Command winget -ErrorAction Stop | Out-Null
Write-Section 'Installing Git, CMake, and Visual Studio C++ Build Tools'
Install-WinGetPackage 'Git.Git'
Install-WinGetPackage 'Kitware.CMake'
Install-WinGetPackage 'Microsoft.VisualStudio.2022.BuildTools' @('--override', '--wait --quiet --add Microsoft.VisualStudio.Workload.VCTools --includeRecommended')
Add-CommonToolPaths
Get-Command git -ErrorAction Stop | Out-Null
Get-Command cmake -ErrorAction Stop | Out-Null
}
function Install-VcpkgSdl2 {
if (-not (Test-Path (Join-Path $VcpkgDirectory '.git'))) {
Write-Section 'Cloning vcpkg'
& git clone https://github.com/microsoft/vcpkg.git $VcpkgDirectory
if ($LASTEXITCODE -ne 0) { Stop-Install 'Could not clone vcpkg.' }
}
$vcpkg = Join-Path $VcpkgDirectory 'vcpkg.exe'
if (-not (Test-Path $vcpkg)) {
Write-Section 'Bootstrapping vcpkg'
& (Join-Path $VcpkgDirectory 'bootstrap-vcpkg.bat') -disableMetrics
if ($LASTEXITCODE -ne 0) { Stop-Install 'Could not bootstrap vcpkg.' }
}
Write-Section 'Installing SDL2'
& $vcpkg install sdl2:x64-windows
if ($LASTEXITCODE -ne 0) { Stop-Install 'Could not install SDL2 through vcpkg.' }
}
function Prepare-WhisperCheckout {
if (-not (Test-Path $WhisperDirectory)) {
Write-Section 'Cloning whisper.cpp'
& git clone $RepoUrl $WhisperDirectory
if ($LASTEXITCODE -ne 0) { Stop-Install 'Could not clone whisper.cpp.' }
return
}
if (-not (Test-Path (Join-Path $WhisperDirectory '.git'))) {
Stop-Install "$WhisperDirectory exists but is not a Git checkout; move it aside and run again."
}
$origin = (& git -C $WhisperDirectory remote get-url origin).Trim()
if ($origin -notin @($RepoUrl, 'https://github.com/ggml-org/whisper.cpp')) {
Stop-Install "$WhisperDirectory is not the official whisper.cpp checkout; refusing to modify it."
}
if ((& git -C $WhisperDirectory status --porcelain)) {
Stop-Install "$WhisperDirectory has uncommitted changes; commit or stash them before running this installer."
}
Write-Section 'Updating whisper.cpp'
& git -C $WhisperDirectory pull --ff-only
if ($LASTEXITCODE -ne 0) { Stop-Install 'Could not update whisper.cpp.' }
}
function Build-Whisper {
$toolchain = Join-Path $VcpkgDirectory 'scripts\buildsystems\vcpkg.cmake'
Write-Section 'Building whisper-stream'
& cmake -S $WhisperDirectory -B (Join-Path $WhisperDirectory 'build') -A x64 -DWHISPER_SDL2=ON "-DCMAKE_TOOLCHAIN_FILE=$toolchain"
if ($LASTEXITCODE -ne 0) { Stop-Install 'CMake configuration failed.' }
& cmake --build (Join-Path $WhisperDirectory 'build') --config Release
if ($LASTEXITCODE -ne 0) { Stop-Install 'whisper.cpp build failed.' }
}
function Get-StreamBinary {
$binary = Get-ChildItem -Path (Join-Path $WhisperDirectory 'build') -Filter 'whisper-stream.exe' -File -Recurse | Select-Object -First 1
if (-not $binary) { Stop-Install 'Installation verification failed: whisper-stream.exe was not built.' }
return $binary.FullName
}
function Get-Model {
if (-not (Test-Path $ModelPath)) {
Write-Section 'Downloading the base English Whisper model'
Invoke-WebRequest -Uri 'https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-base.en.bin' -OutFile $ModelPath
}
if (-not (Test-Path $ModelPath)) { Stop-Install 'Installation verification failed: model was not downloaded.' }
}
function Show-Usage([string]$StreamBinary) {
$TranscriptCommand = "& '$StreamBinary' -m '$ModelPath' --step 0 --length 30000 -vth 0.6 --capture <ID> 2>&1 | Tee-Object -FilePath `"$WhisperDirectory\transcript-`$(Get-Date -Format yyyy-MM-dd_HH-mm-ss).txt`""
@"
Installation complete for Windows.
1. Download VB-CABLE from https://vb-audio.com/Cable/.
2. Extract it, run VBCABLE_Setup_x64.exe as Administrator, then restart Windows.
3. In Zoom > Settings > Audio > Speaker, select CABLE Input (VB-Audio Virtual Cable).
4. In Windows Sound > Recording > CABLE Output > Properties > Listen, enable
Listen to this device and select your headphones, so you still hear the call.
5. Start the command below. It lists capture devices; choose the CABLE Output
device ID with --capture <ID>. Keep Zoom's microphone set to your real mic.
Start transcription:
$TranscriptCommand
The transcript is saved beside whisper.cpp as transcript-YYYY-MM-DD_HH-mm-ss.txt.
Stop transcription with Ctrl-C. Ensure call participants consent where required.
"@ | Write-Host
}
Assert-Windows
if ($VerifyOnly) {
$stream = Get-StreamBinary
if (-not (Test-Path $ModelPath)) { Stop-Install 'Installation verification failed: model was not downloaded.' }
Write-Host 'Installation verification passed.'
exit 0
}
Install-Dependencies
Install-VcpkgSdl2
Prepare-WhisperCheckout
Build-Whisper
$stream = Get-StreamBinary
Get-Model
Show-Usage $stream
#!/usr/bin/env bash
# Installs local live transcription on macOS or Linux.
set -euo pipefail
readonly WHISPER_REPOSITORY='https://github.com/ggml-org/whisper.cpp.git'
readonly WHISPER_DIRECTORY="${WHISPER_DIRECTORY:-${HOME}/whisper.cpp}"
readonly MODEL_PATH="${WHISPER_DIRECTORY}/models/ggml-base.en.bin"
readonly STREAM_BINARY="${WHISPER_DIRECTORY}/build/bin/whisper-stream"
usage() {
cat <<'EOF'
Install local live transcription for macOS system audio, Linux desktop audio, and Windows (using install.ps1).
Usage:
curl -fsSL "<raw-gist-url>/install.sh" | bash
bash install-live-zoom-transcription.sh --verify-only
macOS uses BlackHole and Audio MIDI Setup. Linux uses a PipeWire/PulseAudio sink
monitor. Windows users should run install.ps1 from PowerShell.
EOF
}
die() { printf 'Error: %s\n' "$*" >&2; exit 1; }
info() { printf '\n==> %s\n' "$*"; }
configure_homebrew_path() {
if [[ -x /opt/homebrew/bin/brew ]]; then
eval "$(/opt/homebrew/bin/brew shellenv)"
elif [[ -x /usr/local/bin/brew ]]; then
eval "$(/usr/local/bin/brew shellenv)"
fi
}
install_macos_dependencies() {
if ! xcode-select -p >/dev/null 2>&1; then
info 'Requesting Apple Command Line Tools'
xcode-select --install || true
printf '\nComplete the Apple Command Line Tools dialog, then run this installer again.\n'
exit 0
fi
configure_homebrew_path
if ! command -v brew >/dev/null 2>&1; then
info 'Installing Homebrew'
NONINTERACTIVE=1 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
configure_homebrew_path
fi
command -v brew >/dev/null 2>&1 || die 'Homebrew was not found after installation.'
info 'Installing BlackHole and build dependencies'
brew install blackhole-2ch cmake sdl2 git
}
install_linux_dependencies() {
command -v sudo >/dev/null 2>&1 || die 'Linux installation requires sudo to install packages.'
info 'Installing Linux build and audio-routing dependencies'
if command -v apt-get >/dev/null 2>&1; then
sudo apt-get update
sudo apt-get install -y build-essential cmake libsdl2-dev git curl pavucontrol
elif command -v dnf >/dev/null 2>&1; then
sudo dnf install -y gcc-c++ make cmake SDL2-devel git curl pavucontrol
elif command -v pacman >/dev/null 2>&1; then
sudo pacman -Sy --needed --noconfirm base-devel cmake sdl2 git curl pavucontrol
else
die 'Supported Linux package managers: apt-get, dnf, or pacman.'
fi
command -v pactl >/dev/null 2>&1 || die 'PipeWire/PulseAudio (pactl) is required to capture desktop audio.'
}
prepare_whisper_checkout() {
if [[ ! -e "$WHISPER_DIRECTORY" ]]; then
info 'Cloning whisper.cpp'
git clone "$WHISPER_REPOSITORY" "$WHISPER_DIRECTORY"
return
fi
[[ -d "$WHISPER_DIRECTORY/.git" ]] || die "$WHISPER_DIRECTORY exists but is not a git checkout; move it aside and run again."
local origin
origin=$(git -C "$WHISPER_DIRECTORY" remote get-url origin)
[[ "$origin" == 'https://github.com/ggml-org/whisper.cpp' || "$origin" == "$WHISPER_REPOSITORY" ]] || die "$WHISPER_DIRECTORY is not the official whisper.cpp checkout; refusing to modify it."
[[ -z "$(git -C "$WHISPER_DIRECTORY" status --porcelain)" ]] || die "$WHISPER_DIRECTORY has uncommitted changes; commit or stash them before running this installer."
info 'Updating whisper.cpp'
git -C "$WHISPER_DIRECTORY" pull --ff-only
}
build_and_verify() {
info 'Building whisper-stream'
cmake -S "$WHISPER_DIRECTORY" -B "$WHISPER_DIRECTORY/build" -DWHISPER_SDL2=ON
cmake --build "$WHISPER_DIRECTORY/build" --config Release
if [[ ! -f "$MODEL_PATH" ]]; then
info 'Downloading the base English Whisper model'
bash "$WHISPER_DIRECTORY/models/download-ggml-model.sh" base.en
fi
[[ -x "$STREAM_BINARY" && -f "$MODEL_PATH" ]] || die 'Installation verification failed.'
}
print_macos_steps() {
cat <<'EOF'
Installation complete for macOS.
1. Open Audio MIDI Setup > + > Create Multi-Output Device.
2. Tick both your headphones and BlackHole 2ch.
3. In Zoom > Settings > Audio > Speaker, select that Multi-Output Device.
4. In System Settings > Sound > Input, select BlackHole 2ch.
5. Allow Terminal microphone access when macOS asks.
Start transcription:
TRANSCRIPT_FILE="$HOME/whisper.cpp/transcript-$(date +%Y-%m-%d_%H-%M-%S).txt"
"$HOME/whisper.cpp/build/bin/whisper-stream" -m "$HOME/whisper.cpp/models/ggml-base.en.bin" --step 0 --length 30000 -vth 0.6 2>&1 | tee "$TRANSCRIPT_FILE"
The transcript is saved beside whisper.cpp as transcript-YYYY-MM-DD_HH-MM-SS.txt.
EOF
}
print_linux_steps() {
cat <<'EOF'
Installation complete for Linux.
1. Start the transcription command below, then open pavucontrol.
2. In pavucontrol > Recording, change whisper-stream's source to the monitor of
your active output device (for example, "Built-in Audio Stereo Monitor").
3. Keep Zoom's microphone set to your real microphone; only whisper-stream uses
the monitor source. Audio remains audible through your normal output.
Start transcription:
TRANSCRIPT_FILE="$HOME/whisper.cpp/transcript-$(date +%Y-%m-%d_%H-%M-%S).txt"
"$HOME/whisper.cpp/build/bin/whisper-stream" -m "$HOME/whisper.cpp/models/ggml-base.en.bin" --step 0 --length 30000 -vth 0.6 2>&1 | tee "$TRANSCRIPT_FILE"
The transcript is saved beside whisper.cpp as transcript-YYYY-MM-DD_HH-MM-SS.txt.
EOF
}
main() {
case "${1:-}" in
-h|--help) usage; return 0 ;;
--verify-only)
[[ -x "$STREAM_BINARY" && -f "$MODEL_PATH" ]] || die 'Installation verification failed.'
printf 'Installation verification passed.\n'
return 0
;;
'') ;;
*) usage >&2; die "Unknown option: $1" ;;
esac
case "$(uname -s)" in
Darwin)
install_macos_dependencies
prepare_whisper_checkout
build_and_verify
print_macos_steps
;;
Linux)
install_linux_dependencies
prepare_whisper_checkout
build_and_verify
print_linux_steps
;;
*) die "Unsupported operating system: $(uname -s)" ;;
esac
}
main "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment