# Widephase FFmpeg corresponding source

Widephase 1.x decodes some audio formats with a narrow build of **FFmpeg 8.1.3**, licensed under the **GNU LGPL 2.1 or later**. This page is the corresponding source, the exact patch, and the script we use to build the replaceable dynamic libraries that ship inside the iOS app (`libavutil`, `libavcodec`, `libavformat`, `libswresample`).

## Verify the archive

Either download our copy of `ffmpeg-8.1.3.tar.xz` from this directory, or the identical official file:

https://ffmpeg.org/releases/ffmpeg-8.1.3.tar.xz

SHA-256 (also in `SHA256SUMS`):

```
7138d28c96d9d3e3af4ee3d8cad72741f8ffb40da90c1112235dea3ecd3178a3  ffmpeg-8.1.3.tar.xz
```

If a host rejects the ~11 MB archive, use the official URL and check that hash.

## Apply the only source change

`patch-dst.py` is what our build script runs. `dstdec-8.1.3.patch` is the same change as a unified diff against `libavcodec/dstdec.c`.

1. Uncompressed DST frames: the copy checks that the packet payload length equals `nb_samples * channels` and writes each byte at `dsd[i * 4]`.
2. When `avctx->opaque` is set (Widephase raw DSD): after a full frame is decoded, the four-byte-stride buffer is compacted to lossless MSB-first DSD bytes and the frame format becomes `AV_SAMPLE_FMT_U8`.

```
tar -xf ffmpeg-8.1.3.tar.xz
python3 patch-dst.py ffmpeg-8.1.3
# or: patch -p1 -d ffmpeg-8.1.3 < dstdec-8.1.3.patch
```

## Rebuild the iOS libraries

`build-dsd-decoder.sh` expects this layout (or edit the paths at the top):

- the script lives in `scripts/build-dsd-decoder.sh`
- the archive lives in `ThirdParty/FFmpeg/ffmpeg-8.1.3.tar.xz`
- `scripts/patch-dst.py` is next to the script
- Xcode command-line tools are installed

From that project tree:

```
bash scripts/build-dsd-decoder.sh
```

It configures FFmpeg 8.1.3 with `--enable-shared --disable-static`, `--disable-gpl --disable-nonfree --disable-version3`, only these pieces enabled: decoders `dsd_msbf,dst,flac,ape,wavpack,vorbis,opus`; demuxers `flac,ape,wv,ogg`; parsers `flac,opus,vorbis`; protocol `file`; `swresample`. It builds device arm64 and Simulator arm64+x86_64, packages four dynamic xcframeworks, and a thin static `WidephaseDSD` wrapper that does not contain FFmpeg objects.

Numeric flags stay `-target <ios18 triple> -fPIC` and `-O3` for the wrapper. The build does not use `-ffast-math` or flush-to-zero flags.

## Replace the libraries in the app

On a macOS machine with the Widephase `.app` (or an unpacked IPA):

1. The FFmpeg code lives in `Widephase.app/Frameworks/libavutil.framework`, `libswresample.framework`, `libavcodec.framework` and `libavformat.framework`.
2. After you rebuild, replace those four frameworks with the ones from `ThirdParty/libav*.xcframework` (pick the `ios-arm64` slice for a device build, or the simulator slice for Simulator).
3. Each binary’s install name is `@rpath/<name>.framework/<name>`; sibling libraries use the same `@rpath` names. The app executable already searches `@executable_path/Frameworks`.
4. Re-sign the app and the replaced frameworks with your signing identity (`codesign --force --sign … --timestamp=none` on each framework, then the app bundle). App Store or device installation still requires a valid signature you control.

The thin `WidephaseDSD` static wrapper is Widephase’s own code (not FFmpeg). You do not have to replace it unless you are changing that wrapper.

## Written offer

If you received a copy of Widephase and cannot download these files, email **support@widephase.com** and ask for the corresponding FFmpeg 8.1.3 source, this patch, and this build script for the version you have. We will keep that offer open for at least three years after we last distribute that version, and at least as long as we offer support for it.

Full license text: `COPYING.LGPLv2.1` (also shipped in the app as `FFmpeg-LGPL-2.1.txt`).
