Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 50 additions & 10 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: build

# Every push to main and every pull request, a button in the Actions tab, and version tags
# (v1.2.3), which also publish a GitHub Release with the installer and disk image.
# (v1.2.3), which also publish a GitHub Release with the installers and disk images.
on:
push:
branches: [main]
Expand Down Expand Up @@ -142,11 +142,32 @@ jobs:
path: build/artefacts/*-setup.exe
if-no-files-found: error

# One leg per kind of Mac, each built, tested and validated natively on that kind of Mac rather
# than cross-built: auval and pluginval load the plugin, which an Intel binary cannot do on Apple
# silicon without Rosetta, and the AVX2 Intel build is only proven by running it on Intel.
macos:
name: macOS (Release)
# macos-latest rather than a pinned version: GitHub retires old runner images, and a pinned
# label that has been retired fails before it builds anything.
runs-on: macos-latest
name: macOS ${{ matrix.name }} (Release)
strategy:
# Let both finish, so one failing does not hide what the other would have said. A tag still
# publishes nothing unless both pass: the release job needs the whole matrix.
fail-fast: false
matrix:
include:
# macos-latest rather than a pinned version: GitHub retires old runner images, and a
# pinned label that has been retired fails before it builds anything.
- name: Apple silicon
runner: macos-latest
arch: arm64
artifact: AmpSim-macOS-AppleSilicon
# Pinned, because there is no "latest" Intel label: macos-15-intel is the last Intel
# image GitHub provides, and it is retired in autumn 2027. After that this leg has
# nowhere to run, and the Intel build will have to be cross-built on Apple silicon and
# tested under Rosetta, or dropped.
- name: Intel
runner: macos-15-intel
arch: x86_64
artifact: AmpSim-macOS-Intel
runs-on: ${{ matrix.runner }}

steps:
- uses: actions/checkout@v4
Expand All @@ -159,8 +180,11 @@ jobs:
- name: Install Ninja
run: brew install ninja

# The architecture named rather than left to the runner, so a runner that turned out to be
# the other kind of Mac fails the build instead of quietly producing the wrong one; the
# package step checks every binary against it. AMPSIM_BUILD_TOOLS for the benchmark below.
- name: Configure
run: cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Release
run: cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_ARCHITECTURES=${{ matrix.arch }} -DAMPSIM_BUILD_TOOLS=ON

- name: Build
run: cmake --build build
Expand Down Expand Up @@ -192,16 +216,30 @@ jobs:
--strictness-level 10 \
--validate build/AmpSim_artefacts/Release/VST3/AmpSim.vst3

# Asserts nothing, as on Windows: compare figures only within one job. On the Intel leg it
# also proves the AVX2 build is what was made, since a build without it passes every test
# and only costs more. 48 kHz is the model's own rate; 44.1 kHz puts the resampler in.
- name: Benchmark
run: |
if [ "${{ matrix.arch }}" = x86_64 ]; then
for flag in -mavx2 -mfma; do
grep -q -- "$flag" build/build.ninja || { echo "$flag did not reach the compile lines" >&2; exit 1; }
done
fi
sysctl -n machdep.cpu.brand_string
./build/ampsim_bench 48000
./build/ampsim_bench 44100

# Proves the installer still builds and signs on every run, and is what a tagged run
# publishes.
- name: Package
# Reuses the build above rather than making a second one; the script only has to
# reconfigure to drop the tests.
run: AMPSIM_BUILD_DIR=build ./packaging/package.sh
run: AMPSIM_BUILD_DIR=build AMPSIM_ARCH=${{ matrix.arch }} ./packaging/package.sh

- uses: actions/upload-artifact@v4
with:
name: AmpSim-macOS
name: ${{ matrix.artifact }}
path: build/artefacts/*
if-no-files-found: error

Expand All @@ -223,9 +261,11 @@ jobs:
with:
fetch-depth: 1

# Both Macs' packages, into the one directory: their names already say which is which.
- uses: actions/download-artifact@v4
with:
name: AmpSim-macOS
pattern: AmpSim-macOS-*
merge-multiple: true
path: release

- uses: actions/download-artifact@v4
Expand All @@ -249,7 +289,7 @@ jobs:
--verify-tag <<EOF
AmpSim $version.

**macOS:** Apple silicon, macOS 11 or later. \`.pkg\` installs the Audio Unit, the VST3 and the standalone; \`.dmg\` holds the standalone alone. Ad-hoc signed: the first use needs System Settings > Privacy & Security > Open Anyway.
**macOS:** macOS 11 or later, in two builds. Files ending \`macos-apple-silicon\` are for M-series Macs; files ending \`macos-intel\` are for Intel Macs, which need a processor with AVX2 (every Intel Mac that runs macOS 11 except the 2013 Mac Pro). The installer refuses the wrong one. \`.pkg\` installs the Audio Unit, the VST3 and the standalone; \`.dmg\` holds the standalone alone. Ad-hoc signed: the first use needs System Settings > Privacy & Security > Open Anyway.

**Windows:** Windows 10 version 2004 or later, or Windows 11, on x64 with an AVX2 processor (Intel Core from 2013, any AMD Ryzen). \`setup.exe\` installs the VST3 and the standalone, for you or for everyone. Unsigned: SmartScreen needs More info > Run anyway. In the standalone, choose your interface's ASIO driver in Options for low latency.

Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Build output
build/
build-release/
build-release-*/
cmake-build-*/

# macOS
Expand Down
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,21 @@
What changed in each published release. The [user guide](https://catastrophiccoder.github.io/ampsim/)
describes how the current version behaves; this records what moved between versions.

## [Unreleased]

### Added

- **Intel Macs.** A second macOS build, for Intel Macs on macOS 11 or later with an AVX2
processor — every Intel Mac that runs macOS 11 except the 2013 Mac Pro. It is a separate
package rather than a universal binary.

### Changed

- **The macOS files say which Mac they are for**: `AmpSim-<version>-macos-apple-silicon` and
`AmpSim-<version>-macos-intel`, each as a `.pkg` and a `.dmg`, where there used to be one
unlabelled pair. The installer refuses the wrong one by name, where before the Apple silicon
package would install on an Intel Mac and leave plugins that could not load.

## [0.4.0] — 2026-10-04

**Windows.** The VST3 and the standalone now build, test and install on Windows as well as
Expand Down
21 changes: 17 additions & 4 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -556,7 +556,7 @@ a modelled passive stack. Each is explained where it is implemented.

## What the project is

A **minimal** guitar amp simulator plugin (JUCE, C++17), built as AU / VST3 / Standalone on macOS and as VST3 / Standalone on Windows. Four parts, per the Goal section of `ampsim_plan.md`:
A **minimal** guitar amp simulator plugin (JUCE, C++17), built as AU / VST3 / Standalone on macOS (Apple silicon and Intel, separately) and as VST3 / Standalone on Windows. Four parts, per the Goal section of `ampsim_plan.md`:

1. **Amp** — a pre-trained `.nam` model run through [NeuralAmpModelerCore](https://github.com/sdatkinson/NeuralAmpModelerCore) (MIT). No hand-written amp DSP; the model supplies the tone.
2. **Custom amp-like UI** — a front panel with Gain, three-band EQ (Bass, Mid, Treble) and Master Volume. This is the project's own contribution and the reason it is not just a NAM loader.
Expand Down Expand Up @@ -647,9 +647,22 @@ commit and push, then
git tag -a vX.Y.Z -m "AmpSim X.Y.Z" && git push origin vX.Y.Z # after the version commit is pushed
```

The runner is `macos-latest`, which is Apple silicon, and nothing sets `CMAKE_OSX_ARCHITECTURES`,
so the published build is arm64 against a deployment target of macOS 11. The Windows build is x64
and needs AVX2 and Windows 10 2004 or later, which the installer checks.
**There are two Mac builds, not one universal binary**: `AmpSim-<version>-macos-apple-silicon`
and `-macos-intel`, each a `.pkg` and a `.dmg`, both against a deployment target of macOS 11. The
macOS job is a matrix, and each leg builds, tests and validates on its own kind of Mac:
`macos-latest` for arm64 and `macos-15-intel` for x86_64. That Intel label is the last GitHub
offers and is retired in autumn 2027; after that the Intel build has to be cross-built on Apple
silicon and tested under Rosetta, which runs AVX2 (all 126 tests passed that way) though
`sysctl hw.optional.avx2_0` says 0 under it. `package.sh` takes `AMPSIM_ARCH`, refuses a binary
`lipo` says is the other architecture, and turns off `AMPSIM_COPY_PLUGIN` for a cross build so an
Intel AU never replaces the one the hosts on an Apple silicon Mac load.

**The Intel Mac build is AVX2 and FMA**, `-mavx2 -mfma` in `CMakeLists.txt`, for the reason the
Windows build is; clang does not imply FMA from AVX2 the way MSVC's `/arch:AVX2` does. The
installer's `installation-check` in `packaging/distribution.xml` refuses an Intel package on
Apple silicon, an Apple silicon one on Intel, and an Intel Mac without AVX2 (only the 2013 Mac Pro
among those macOS 11 supports). The Windows build is x64 and needs AVX2 and Windows 10 2004 or
later, which its installer checks.

## What it costs

Expand Down
10 changes: 10 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,16 @@ if(MSVC)
add_compile_options(/arch:AVX2)
endif()

# The Intel Mac build makes the same choice, for the same reason. Every Intel Mac that runs
# macOS 11 has AVX2 except the 2013 Mac Pro, and the installer refuses that one (see
# packaging/distribution.xml). AVX2 does not bring FMA with it on clang the way /arch:AVX2 does
# on MSVC, so ask for both. A single-architecture build only: there is no AVX2 on arm64, and a
# universal build would need the flags per slice, which nothing here produces.
if(APPLE AND (CMAKE_OSX_ARCHITECTURES STREQUAL "x86_64"
OR (NOT CMAKE_OSX_ARCHITECTURES AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")))
add_compile_options(-mavx2 -mfma)
endif()

# The C++ runtime linked statically on Windows (/MT), so the standalone and the VST3 need nothing
# installed beside them. CMake's default is the DLL runtime, and a plugin that cannot find
# VCRUNTIME140.dll fails to load in the host with no useful message. A variable rather than a
Expand Down
12 changes: 7 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,11 @@ it so the repeats are of the already-distorted tone.

Ready-made packages are on the [releases page](https://github.com/CatastrophicCoder/ampsim/releases).

**macOS** (Apple silicon, macOS 11 or later): the `.pkg` installs the AU and VST3 into
`/Library/Audio/Plug-Ins/` and the standalone app into `/Applications`; the `.dmg` holds just the
app. In Logic the plugin appears as **Catastrophic Audio: AmpSim**, with the other amps and
**macOS** (macOS 11 or later): take the files ending `macos-apple-silicon` for an M-series Mac
and `macos-intel` for an Intel one, which needs AVX2 — every Intel Mac that runs macOS 11 has it
except the 2013 Mac Pro. The installer refuses the wrong one. The `.pkg` installs the AU and VST3
into `/Library/Audio/Plug-Ins/` and the standalone app into `/Applications`; the `.dmg` holds just
the app. In Logic the plugin appears as **Catastrophic Audio: AmpSim**, with the other amps and
distortion plugins.

**Windows** (Windows 10 version 2004 or later, or 11, on x64 with an AVX2 processor): the
Expand Down Expand Up @@ -235,8 +237,8 @@ assistant.

## What it does not do

- **macOS on Apple silicon, and Windows on x64 with AVX2.** No Linux build, no Intel Mac build,
and no native Windows-on-ARM build: there the x64 build loads only in an x64 host.
- **macOS on Apple silicon or Intel with AVX2, and Windows on x64 with AVX2.** No Linux build, no
universal Mac binary — two separate packages instead — and no native Windows-on-ARM build: there the x64 build loads only in an x64 host.
- **Mono.** Stereo input is summed at the top of the chain.
- **One model, one cabinet, no channel switching.**
- **The mic-position blend is unproven musically.** The interpolation is exact and tested, but
Expand Down
6 changes: 5 additions & 1 deletion docs/guide/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,11 @@ <h1>AmpSim user guide</h1>
<section id="install">
<h2>Installing</h2>
<h3>macOS</h3>
<p>Apple silicon, macOS 11 or later. The installer puts three things on your machine: an <b>Audio Unit</b>
<p>macOS 11 or later, on Apple silicon or an Intel Mac. There is a package for each: the files
ending <code>macos-apple-silicon</code> are for M-series Macs, and those ending
<code>macos-intel</code> for Intel ones, which need a processor with AVX2 &mdash; every Intel
Mac that runs macOS 11 has it except the 2013 Mac Pro. The installer checks, and refuses the
wrong one. It puts three things on your machine: an <b>Audio Unit</b>
and a <b>VST3</b> in <code>/Library/Audio/Plug-Ins/</code>, and a <b>standalone app</b> in
<code>/Applications</code>. Take whichever you need.</p>
<ol>
Expand Down
30 changes: 26 additions & 4 deletions packaging/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,37 @@ false. Anything added to the installer later needs the same treatment.

It builds Release, ad-hoc signs the three formats, and writes to `build-release/artefacts`:

- `AmpSim-<version>.pkg` — an installer offering the AU, the VST3 and the standalone app
separately. Installs to `/Library/Audio/Plug-Ins/` and `/Applications`, so it asks for an
- `AmpSim-<version>-<platform>.pkg` — an installer offering the AU, the VST3 and the standalone
app separately. Installs to `/Library/Audio/Plug-Ins/` and `/Applications`, so it asks for an
administrator password.
- `AmpSim-<version>.dmg` — the standalone app alone, with a link to Applications to drag it into.
- `AmpSim-<version>-<platform>.dmg` — the standalone app alone, with a link to Applications to drag
it into.

`<platform>` is `macos-apple-silicon` or `macos-intel`. The script builds for the Mac it runs on;
`AMPSIM_ARCH` picks the other one:

```sh
AMPSIM_ARCH=x86_64 ./packaging/package.sh # Intel, into build-release-x86_64/artefacts
AMPSIM_ARCH=arm64 ./packaging/package.sh # Apple silicon, from an Intel Mac
```

A build for the other kind of Mac goes in a tree of its own and is not copied into
`~/Library/Audio/Plug-Ins`, where it would replace the plugin this Mac's hosts load. The script
checks every binary with `lipo` before packaging it, so a build tree configured for the wrong Mac
fails rather than producing a package with the wrong name.

The two are separate packages rather than one universal binary. The Intel build is compiled for
AVX2, as the Windows build is (`docs/windows.md` has the measurements), and that takes
per-architecture compiler flags. Each package's installer checks the Mac it is opened on and
refuses the wrong one by name, and the Intel one also refuses a processor without AVX2 — of the
Macs that run macOS 11, only the 2013 Mac Pro. The Intel build runs under Rosetta on Apple silicon,
AVX2 included, which is how to run its tests on an M-series Mac; Rosetta's own overhead makes its
benchmark figures meaningless there.

To install without an administrator password, into your own library rather than the system one:

```sh
installer -pkg build-release/artefacts/AmpSim-*.pkg -target CurrentUserHomeDirectory
installer -pkg build-release/artefacts/AmpSim-*-macos-apple-silicon.pkg -target CurrentUserHomeDirectory
```

That puts the plugins in `~/Library/Audio/Plug-Ins/` and the app in `~/Applications`, which every
Expand Down
37 changes: 36 additions & 1 deletion packaging/distribution.xml
Original file line number Diff line number Diff line change
@@ -1,8 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<installer-gui-script minSpecVersion="2">
<title>AmpSim @VERSION@</title>
<title>AmpSim @VERSION@ for @MAC@</title>
<welcome file="welcome.html" mime-type="text/html"/>
<!-- Both architectures, so the installer runs natively on either Mac and the check below,
rather than Rosetta or a generic refusal, is what tells someone they have the wrong one. -->
<options customize="always" require-scripts="false" hostArchitectures="arm64,x86_64"/>
<installation-check script="suitsThisMac()"/>
<script><![CDATA[
// package.sh substitutes the architecture this package was built for.
var builtFor = '@ARCH@';

function refuse(message) {
my.result.type = 'Fatal';
my.result.title = 'This is the wrong AmpSim for this Mac';
my.result.message = message;
return false;
}

function suitsThisMac() {
// hw.optional.arm64 is 1 on Apple silicon, even when the installer runs under Rosetta.
var appleSilicon = system.sysctl('hw.optional.arm64') == 1;

if (builtFor == 'arm64' && !appleSilicon)
return refuse('This package is for Macs with Apple silicon. This Mac has an Intel ' +
'processor: download the AmpSim package whose name ends in macos-intel.');

if (builtFor == 'x86_64' && appleSilicon)
return refuse('This package is for Intel Macs. This Mac has Apple silicon: download ' +
'the AmpSim package whose name ends in macos-apple-silicon.');

// The Intel build is compiled for AVX2 (CMakeLists.txt). Without it the plugin would crash
// its host on the first block rather than refuse to load. The 2013 Mac Pro is the one Mac
// that runs macOS 11 and lacks it.
if (builtFor == 'x86_64' && system.sysctl('hw.optional.avx2_0') != 1)
return refuse('AmpSim needs a processor with AVX2, which this Mac does not have.');

return true;
}
]]></script>

<choices-outline>
<line choice="au"/>
Expand Down
Loading
Loading