BWF Analyser: browser page and macOS app

Reads and edits BWF metadata for production sound. One source tree builds a
single self-contained page and a native Tauri app with a Rust audio engine and
WAV writer. Around 370 checks across seven test suites.

First commit of the existing state, so that from here every change can be
seen and undone.
This commit is contained in:
2026-08-17 22:50:39 +08:00
commit 2d0b7fe8b5
50 changed files with 42383 additions and 0 deletions
+138
View File
@@ -0,0 +1,138 @@
#!/usr/bin/env python3
"""Draws the app icon and packs the .icns, with no Xcode tooling involved.
macOS rounds the corners of nothing: an app icon has to bring its own squircle.
This draws one at 1024px, puts a waveform on it, then downsamples to the sizes
macOS asks for. The .icns container is written by hand — it is just a header
plus one length-prefixed PNG per size.
"""
import math
import pathlib
import struct
from PIL import Image, ImageDraw
OUT = pathlib.Path(__file__).resolve().parent.parent / "mac-app" / "src-tauri" / "icons"
BASE = 1024
SUPERSAMPLE = 2 # draw big, shrink down: cheap anti-aliasing
BACKGROUND_TOP = (39, 39, 42)
BACKGROUND_BOTTOM = (24, 24, 27)
WAVE = (250, 250, 250)
ACCENT = (96, 165, 250)
def squircle_mask(size, radius_ratio=0.2237):
"""Apple's icon shape is close enough to a rounded rect at this radius."""
mask = Image.new("L", (size, size), 0)
draw = ImageDraw.Draw(mask)
inset = int(size * 0.085)
box = [inset, inset, size - inset, size - inset]
draw.rounded_rectangle(box, radius=int(size * radius_ratio), fill=255)
return mask
def vertical_gradient(size, top, bottom):
gradient = Image.new("RGB", (1, size))
for y in range(size):
t = y / max(1, size - 1)
gradient.putpixel(
(0, y),
tuple(int(top[i] + (bottom[i] - top[i]) * t) for i in range(3)),
)
return gradient.resize((size, size), Image.NEAREST)
def draw_icon(size):
canvas = Image.new("RGBA", (size, size), (0, 0, 0, 0))
canvas.paste(vertical_gradient(size, BACKGROUND_TOP, BACKGROUND_BOTTOM), (0, 0))
canvas.putalpha(squircle_mask(size))
draw = ImageDraw.Draw(canvas)
# A waveform: a few overlaid sines so it reads as audio rather than a
# perfect textbook sine.
centre = size / 2
left = size * 0.20
right = size * 0.80
span = right - left
bars = 23
bar_width = span / (bars * 1.9)
gap = (span - bars * bar_width) / (bars - 1)
for index in range(bars):
phase = index / (bars - 1)
envelope = (
0.55 * math.sin(phase * math.pi)
+ 0.30 * math.sin(phase * math.pi * 3.7 + 0.6)
+ 0.18 * math.sin(phase * math.pi * 7.3 + 1.9)
)
height = abs(envelope) * size * 0.30 + size * 0.022
x0 = left + index * (bar_width + gap)
colour = ACCENT if index % 5 == 2 else WAVE
draw.rounded_rectangle(
[x0, centre - height, x0 + bar_width, centre + height],
radius=bar_width / 2,
fill=colour,
)
return canvas
def render(size):
big = draw_icon(size * SUPERSAMPLE)
return big.resize((size, size), Image.LANCZOS)
def write_icns(path, images):
"""ICNS: 'icns' + total length, then (type, length, PNG payload) records."""
# Type codes macOS reads PNG data from, per size.
types = {
16: b"icp4",
32: b"icp5",
64: b"icp6",
128: b"ic07",
256: b"ic08",
512: b"ic09",
1024: b"ic10",
}
chunks = []
for size, png in images.items():
if size not in types:
continue
chunks.append(types[size] + struct.pack(">I", len(png) + 8) + png)
body = b"".join(chunks)
path.write_bytes(b"icns" + struct.pack(">I", len(body) + 8) + body)
def main():
OUT.mkdir(parents=True, exist_ok=True)
sizes = [16, 32, 64, 128, 256, 512, 1024]
rendered = {size: render(size) for size in sizes}
# What tauri.conf.json points at.
rendered[32].save(OUT / "32x32.png")
rendered[128].save(OUT / "128x128.png")
rendered[256].save(OUT / "128x128@2x.png")
rendered[512].save(OUT / "icon.png")
pngs = {}
for size, image in rendered.items():
temp = OUT / ("_%d.png" % size)
image.save(temp)
pngs[size] = temp.read_bytes()
temp.unlink()
write_icns(OUT / "icon.icns", pngs)
for name in ("32x32.png", "128x128.png", "128x128@2x.png", "icon.png", "icon.icns"):
print("%-16s %6d bytes" % (name, (OUT / name).stat().st_size))
if __name__ == "__main__":
main()