Skip to content

Commit

Permalink
Enable Metal support on macOS
Browse files Browse the repository at this point in the history
  • Loading branch information
Dharma Bellamkonda authored and dharmab committed Nov 29, 2024
1 parent d19e9d3 commit 924ba42
Show file tree
Hide file tree
Showing 8 changed files with 72 additions and 55 deletions.
24 changes: 10 additions & 14 deletions .github/actions/build-whisper/action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ inputs:
whisper-cpp-version:
description: 'The version of whisper.cpp to use'
required: true
default: 'v1.6.2-openmp'
default: 'v1.7.2-windows-fix'
os:
description: 'The operating system to build for'
required: true
Expand All @@ -21,10 +21,6 @@ inputs:
description: 'The shell to use'
required: true
default: 'bash'
cc:
description: 'The C compiler to use'
required: true
default: 'gcc'
runs:
using: composite
steps:
Expand All @@ -33,9 +29,10 @@ runs:
uses: actions/cache/restore@v4
with:
path: |
third_party/whisper.cpp/libwhisper.a
third_party/whisper.cpp/*.h
key: whisper-${{ inputs.whisper-cpp-version }}-${{ inputs.os }}-{{ inputs.arch }}-cache
third_party/whisper.cpp/*whisper.a
third_party/whisper.cpp/include/*.h
third_party/whisper.cpp/include/ggml/*.h
key: whisper-${{ inputs.whisper-cpp-version }}-${{ inputs.os }}-${{ inputs.arch }}-10-cache
- name: Checkout whisper.cpp
if: steps.cache-whisper-restore.outputs.cache-hit != 'true'
uses: actions/checkout@v4
Expand All @@ -45,14 +42,12 @@ runs:
ref: ${{ inputs.whisper-cpp-version }}
- name: Build whisper.cpp
if: steps.cache-whisper-restore.outputs.cache-hit != 'true'
env:
CC: ${{ inputs.cc }}
shell: ${{ inputs.shell }}
run: make whisper
- name: Set whisper paths
shell: ${{ inputs.shell }}
run: |
echo "C_INCLUDE_PATH=${{ github.workspace }}/third_party/whisper.cpp/" >> $GITHUB_ENV
echo "C_INCLUDE_PATH=${{ github.workspace }}/third_party/whisper.cpp/include:{{ github.workspace }}/third_party/whisper.cpp/ggml/include" >> $GITHUB_ENV
echo "LIBRARY_PATH=${{ github.workspace }}/third_party/whisper.cpp/" >> $GITHUB_ENV
echo "GOARCH=${{ inputs.arch }}" >> $GITHUB_ENV
- name: Save whisper.cpp artifacts
Expand All @@ -61,6 +56,7 @@ runs:
uses: actions/cache/save@v4
with:
path: |
third_party/whisper.cpp/libwhisper.a
third_party/whisper.cpp/*.h
key: ${{ steps.cache-whisper-restore.outputs.cache-primary-key }}
third_party/whisper.cpp/*whisper.a
third_party/whisper.cpp/include/*.h
third_party/whisper.cpp/include/ggml/*.h
key: ${{ steps.cache-whisper-restore.outputs.cache-primary-key }}
4 changes: 1 addition & 3 deletions .github/workflows/skyeye.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,6 @@ jobs:
with:
os: macos
arch: arm64
cc: clang
- name: Build SkyEye
run: make skyeye
- name: Build SkyEye Scaler
Expand Down Expand Up @@ -134,7 +133,6 @@ jobs:
mingw-w64-ucrt-x86_64-toolchain
mingw-w64-ucrt-x86_64-opus
mingw-w64-ucrt-x86_64-libsoxr
mingw-w64-ucrt-x86_64-openblas
mingw-w64-ucrt-x86_64-gcc
mingw-w64-ucrt-x86_64-go
mingw-w64-ucrt-x86_64-curl
Expand Down Expand Up @@ -242,4 +240,4 @@ jobs:
registry-password: ${{ secrets.GITHUB_TOKEN }}
image-name: ${{ github.repository }}-scaler
target: skyeye-scaler
skyeye-version: ${{ env.GITHUB_REF_NAME }}
skyeye-version: ${{ env.GITHUB_REF_NAME }}
2 changes: 0 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ RUN apt-get update && apt-get install -y \
gcc \
libopus-dev \
libsoxr-dev \
libopenblas-openmp-dev \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /skyeye
COPY third_party third_party
Expand All @@ -26,7 +25,6 @@ FROM debian:bookworm-slim AS skyeye
RUN apt-get update && apt-get install -y \
libopus0 \
libsoxr0 \
libopenblas0-openmp \
&& rm -rf /var/lib/apt/lists/*
COPY --from=builder /skyeye/skyeye /opt/skyeye/bin/skyeye
ENTRYPOINT ["/opt/skyeye/bin/skyeye"]
Expand Down
51 changes: 29 additions & 22 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -16,31 +16,43 @@ else
OS_DISTRIBUTION := $(shell lsb_release -si)
endif


# Source code paths
SKYEYE_PATH = $(shell pwd)
SKYEYE_SOURCES = $(shell find . -type f -name '*.go')
SKYEYE_SOURCES += go.mod go.sum
SKYEYE_BIN = skyeye
SKYEYE_SCALER_BIN = skyeye-scaler

WHISPER_CPP_PATH = third_party/whisper.cpp
LIBWHISPER_PATH = $(WHISPER_CPP_PATH)/libwhisper.a
WHISPER_H_PATH = $(WHISPER_CPP_PATH)/whisper.h
WHISPER_H_PATH = $(WHISPER_CPP_PATH)/include/whisper.h
WHISPER_CPP_REPO = https://github.com/dharmab/whisper.cpp.git
WHISPER_CPP_VERSION = v1.6.2-openmp
WHISPER_CPP_VERSION = v1.7.2-windows-fix
WHISPER_CPP_BUILD_ENV =

# Compiler variables and flags
GOBUILDVARS = GOARCH=$(GOARCH)
ABS_WHISPER_CPP_PATH = $(abspath $(WHISPER_CPP_PATH))
BUILD_VARS = CGO_ENABLED=1 \
C_INCLUDE_PATH="$(SKYEYE_PATH)/$(WHISPER_CPP_PATH)" \
LIBRARY_PATH="$(SKYEYE_PATH)/$(WHISPER_CPP_PATH)"
C_INCLUDE_PATH="$(ABS_WHISPER_CPP_PATH)/include:$(ABS_WHISPER_CPP_PATH)/ggml/include" \
LIBRARY_PATH="$(ABS_WHISPER_CPP_PATH)"
BUILD_FLAGS = -tags nolibopusfile

# Populate --version from Git tag
ifeq ($(SKYEYE_VERSION),)
SKYEYE_VERSION=$(shell git describe --tags || echo devel)
endif
LDFLAGS= -X "main.Version=$(SKYEYE_VERSION)"
LDFLAGS= -X "main.Version=$(SKYEYE_VERSION) -fopenmp"

# macOS-specific settings
ifeq ($(OS_DISTRIBUTION),macOS)
# Use Homebrew LLVM/Clang for OpenMP support
CC=$(shell brew --prefix llvm)/bin/clang
CXX=$(shell brew --prefix llvm)/bin/clang++
BUILD_VARS += CC=$(CC) CXX=$(CXX)
# Enable GPU acceleration
WHISPER_CPP_BUILD_ENV = GGML_METAL=1
endif

# Windows-specific settings
ifeq ($(OS_DISTRIBUTION),Windows)
Expand All @@ -51,11 +63,11 @@ SKYEYE_SCALER_BIN = skyeye-scaler.exe
GO = /ucrt64/bin/go
GOBUILDVARS += GOROOT="/ucrt64/lib/go" GOPATH="/ucrt64"
# Static linking on Windows to avoid MSYS2 dependency at runtime
LIBRARIES = opus soxr openblas
LIBRARIES = opus soxr
CFLAGS = $(pkg-config $(LIBRARIES) --cflags --static)
BUILD_VARS += CFLAGS=$(CFLAGS)
EXTLDFLAGS = $(pkg-config $(LIBRARIES) --libs --static)
LDFLAGS += -linkmode external -extldflags "$(EXTLDFLAGS) -static -fopenmp"
LDFLAGS += -linkmode external -extldflags "$(EXTLDFLAGS) -static"
endif

BUILD_VARS += LDFLAGS='$(LDFLAGS)'
Expand All @@ -73,8 +85,7 @@ install-msys2-dependencies:
$(MINGW_PACKAGE_PREFIX)-toolchain \
$(MINGW_PACKAGE_PREFIX)-go \
$(MINGW_PACKAGE_PREFIX)-opus \
$(MINGW_PACKAGE_PREFIX)-libsoxr \
$(MINGW_PACKAGE_PREFIX)-openblas
$(MINGW_PACKAGE_PREFIX)-libsoxr

.PHONY: install-arch-linux-dependencies
install-arch-linux-dependencies:
Expand All @@ -83,8 +94,7 @@ install-arch-linux-dependencies:
base-devel \
go \
opus \
libsoxr \
openblas
libsoxr

.PHONY: install-debian-dependencies
install-debian-dependencies:
Expand All @@ -95,25 +105,22 @@ install-debian-dependencies:
libopus-dev \
libopus0 \
libsoxr-dev \
libsoxr0 \
libopenblas0-openmp \
libopenblas-openmp-dev \
libsoxr0

.PHONY: install-macos-dependencies
install-macos-dependencies:
xcode-select --install || true
brew install \
git \
go \
opus \
libsoxr

WHISPER_CPP_BUILD_ENV =
ifneq ($(OS_DISTRIBUTION),macOS)
WHISPER_CPP_BUILD_ENV = GGML_OPENBLAS=1
endif
libomp \
libsoxr \
llvm \
opus

$(LIBWHISPER_PATH) $(WHISPER_H_PATH):
if [ ! -f $(LIBWHISPER_PATH) -o ! -f $(WHISPER_H_PATH) ]; then git -C "$(WHISPER_CPP_PATH)" checkout --quiet $(WHISPER_CPP_VERSION) || git clone --depth 1 --branch $(WHISPER_CPP_VERSION) -c advice.detachedHead=false "$(WHISPER_CPP_REPO)" "$(WHISPER_CPP_PATH)" && $(WHISPER_CPP_BUILD_ENV) make -C $(WHISPER_CPP_PATH)/bindings/go whisper; fi
if [ -f third_party/whisper.cpp/whisper.a ] && [ ! -f third_party/whisper.cpp/libwhisper.a ]; then cp third_party/whisper.cpp/whisper.a third_party/whisper.cpp/libwhisper.a; fi

.PHONY: whisper
whisper: $(LIBWHISPER_PATH) $(WHISPER_H_PATH)
Expand Down
39 changes: 29 additions & 10 deletions docs/ADMIN.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ This is a technical article on how to deploy SkyEye, targeted at multiplayer ser

SkyEye works best when run on a dedicated system, separate from the DCS World and SRS servers.

_Recommended Architecture: DCS, TacView and SRS on one Windows server. SkyEye on another Linux server._
_Recommended Architecture: DCS, TacView and SRS on one Windows server. SkyEye on another Linux or macOS server._

```mermaid
flowchart LR
dcs[Windows<br/>DCS World Server<br/>TacView Exporter<br/>SRS Server] <--> skyeye[Linux<br/>SkyEye]
dcs[Windows<br/>DCS World Server<br/>TacView Exporter<br/>SRS Server] <--> skyeye[Linux/macOS<br/>SkyEye]
```

If you insist on running SkyEye on the same system as DCS, I cannot offer you any guarantees of performance. If you choose to try this anyway, I do recommend configuring Process Affinity to pin SkyEye to a set of dedicated CPU cores separate from any other CPU-intensive software. The easiest way to do this on Windows is by using the [CPU Affinities feature in Process Lasso](https://bitsum.com/processlasso-docs/#default_affinities).
Expand All @@ -26,27 +26,28 @@ SkyEye will automatically reconnect to TacView if the connection is lost. Howeve

## Software

SkyEye is officially supported on Windows and Linux. The Windows version bundles all required libraries within skyeye.exe. The Linux version
requires Opus, SOXR and OpenBLAS to be installed using the OS package manager.
SkyEye is officially supported on Windows AMD64, Linux AMD64 and Apple Silicon. The Windows version bundles all required libraries within skyeye.exe. The Linux version requires Opus and SOXR to be installed using the OS package manager. The macOS version requires Opus and SOXR to be installed using Homebrew.

## Hardware

SkyEye requires a fast, multithreaded, **dedicated** CPU, 3GB of RAM, and about 2GB of disk space. The CPU must have support for [AVX2](https://en.wikipedia.org/wiki/Advanced_Vector_Extensions#Advanced_Vector_Extensions_2).
SkyEye requires a fast, multithreaded, **dedicated** CPU, 3GB of RAM, and about 2GB of disk space. On AMD64, the CPU must have support for [AVX2](https://en.wikipedia.org/wiki/Advanced_Vector_Extensions#Advanced_Vector_Extensions_2).

CPU Series|AVX2 Added In
-|-
Intel Core|Haswell (2013)
AMD|Excavator (2015)
Intel Pentium/Celeron|Tiger Lake (2020)

SkyEye currently only officially supports the AMD64 (x86-64) CPU architecture; ARM CPUs are not yet officially supported. I've found that at least 4 dedicated CPU cores are needed for a good experience, but this may differ by the exact CPU being used, so experiment and see what works well for you.
SkyEye currently only officially supports the AMD64 (x86-64) and Apple Sillicon CPU architectures; ARM CPUs are not yet officially supported on Windows and Linux. On Windows and Linux I've found that at least 4 dedicated CPU cores are needed for a good experience, but this may differ by the exact CPU being used, so experiment and see what works well for you. On macOS, SkyEye uses GPU acceleration for some operations, so CPU load is lower.

It is important that the CPU cores be **dedicated** cores. Shared core virtual machines are **not supported** and will result in **high latency and stuttering audio.**

Non-scientific speech recognition performance:

System|CPU|Speech Recognition Model|Speech Recognition Time (Synthetic benchmark)|Speech Recognition Time (In practice)
-|-|-|-|-
M4 Mac Mini|Apple M4|ggml-small.en.bin|0.25-0.5s|?
M4 Mac Mini|Apple M4|ggml-medium.en.bin|0.9-1.0s|?
My current PC|AMD 5900X|ggml-small.en.bin|1.0-1.5s|1.5-2.0s
My older PC|AMD 3900XT|ggml-small.en.bin|2-3s|?
Vultr Optimized Cloud (CPU Optimized)|AMD EPYC Milan (4 dedicated cores)|ggml-small.en.bin|3.0-3.5s|3.0-3.5s
Expand Down Expand Up @@ -130,7 +131,9 @@ I recommend you retain your logs so that you can include them in any bug reports

On Linux, the easiest way to retain your logs is to run SkyEye as a systemd-managed service. This will automatically retain your logs in the system journal, and you'll be able to query and search the logs using `journalctl -u skyeye`.

On Windows, the easiest way to retain your logs is to use [redirection](https://learn.microsoft.com/en-us/troubleshoot/developer/visualstudio/cpp/language-compilers/redirecting-error-command-prompt).
On macOS, the easiest way to retain your logs is to pipe the output of SkyEye to a file using `tee`.

On Windows, SkyEye is bundled with WinSW and a service configuration file which will log to a file.

Advanced users should consider sending their logs to a log aggregator such as [Grafana Cloud](https://grafana.com/products/cloud/logs/). If you do this, I also recommend using `--log-format=json` to log in JSON format, which is easier to search and filter when using an aggregator.

Expand Down Expand Up @@ -187,19 +190,19 @@ A sample [cloud-init](https://cloudinit.readthedocs.io/en/latest/) config is pro

### Manual Installation

Install shared libraries for [Opus](https://opus-codec.org/), [SoX Resampler](https://sourceforge.net/p/soxr/wiki/Home/) and [OpenBLAS](http://www.openblas.net/) with [OpenMP](https://www.openmp.org/about/openmp-faq/#OMPAPI).
Install shared libraries for [Opus](https://opus-codec.org/) and [SoX Resampler](https://sourceforge.net/p/soxr/wiki/Home/).

Ubuntu:

```bash
sudo apt-get update
sudo apt-get install libopus0 libsoxr0 libopenblas0-openmp
sudo apt-get install libopus0 libsoxr0
```

Arch Linux:

```bash
sudo pacman -Syu opus soxr openblas
sudo pacman -Syu opus soxr
```

Download SkyEye and an AI model. Copy them to `/opt/skyeye/`. Create a `skyeye` user to run SkyEye.
Expand Down Expand Up @@ -279,6 +282,22 @@ journalctl -u skyeye
journalctl -u skyeye > skyeye.log
```

## macOS

_Work in Progress_

Download the SkyEye release ZIP from the [releases page](https://github.com/dharmab/skyeye/releases) and extract it.

Download an AI model.

Edit `config.yaml` as required.

Open Terminal and run:

```sh
./skyeye --config-file=config.yaml | tee skyeye.log
```

## Windows

Download the SkyEye release ZIP from the [releases page](https://github.com/dharmab/skyeye/releases) and extract it.
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ require (
github.com/bwmarrin/discordgo v0.28.1
github.com/dharmab/goacmi v1.0.2
github.com/gammazero/deque v0.2.1
github.com/ggerganov/whisper.cpp/bindings/go v0.0.0-20240727173504-6739eb83c3ca
github.com/ggerganov/whisper.cpp/bindings/go v0.0.0-20241121150429-8c6a9b8bb6a0
github.com/golangci/golangci-lint v1.60.3
github.com/gopxl/beep/v2 v2.0.3
github.com/hbollon/go-edlib v1.6.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,8 @@ github.com/fzipp/gocyclo v0.6.0 h1:lsblElZG7d3ALtGMx9fmxeTKZaLLpU8mET09yN4BBLo=
github.com/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA=
github.com/gammazero/deque v0.2.1 h1:qSdsbG6pgp6nL7A0+K/B7s12mcCY/5l5SIUpMOl+dC0=
github.com/gammazero/deque v0.2.1/go.mod h1:LFroj8x4cMYCukHJDbxFCkT+r9AndaJnFMuZDV34tuU=
github.com/ggerganov/whisper.cpp/bindings/go v0.0.0-20240727173504-6739eb83c3ca h1:s1f7gd0NpwAdjyAcJvn03TnQqQZTJojXtmdfPy7kTOk=
github.com/ggerganov/whisper.cpp/bindings/go v0.0.0-20240727173504-6739eb83c3ca/go.mod h1:QIjZ9OktHFG7p+/m3sMvrAJKKdWrr1fZIK0rM6HZlyo=
github.com/ggerganov/whisper.cpp/bindings/go v0.0.0-20241121150429-8c6a9b8bb6a0 h1:vSv0WhsCkhau0BdC1H7Q2lHR8pzz0skaQkXZdEPYp/4=
github.com/ggerganov/whisper.cpp/bindings/go v0.0.0-20241121150429-8c6a9b8bb6a0/go.mod h1:qyHjS/50ORo01H0NsuEEGsQR9VCtOcEye0gUl2sx1s8=
github.com/ghostiam/protogetter v0.3.6 h1:R7qEWaSgFCsy20yYHNIJsU9ZOb8TziSRRxuAOTVKeOk=
github.com/ghostiam/protogetter v0.3.6/go.mod h1:7lpeDnEJ1ZjL/YtyoN99ljO4z0pd3H0d18/t2dPBxHw=
github.com/go-audio/audio v1.0.0 h1:zS9vebldgbQqktK4H0lUqWrG8P0NxCJVqcj7ZpNnwd4=
Expand Down
1 change: 0 additions & 1 deletion init/cloud-init/ubuntu.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ users:
packages:
- libopus0
- libsoxr0
- libopenblas0-openmp
package_update: true
package_upgrade: true
write_files:
Expand Down

0 comments on commit 924ba42

Please sign in to comment.