Music Notation
ci / checks (push) Successful in 43m19s

This commit is contained in:
khodowany
2026-09-15 01:30:42 -05:00
parent fe42d811fa
commit 1d1bd3e871
41 changed files with 1546 additions and 5236 deletions
-36
View File
@@ -1,36 +0,0 @@
"""Extract notation glyph bounds from the shipped OTF, in staff-space units."""
import argparse
from pathlib import Path
from fontTools.pens.boundsPen import BoundsPen
from fontTools.ttLib import TTFont
def generate(font_path, output):
with TTFont(font_path) as font:
glyphs, cmap = font.getGlyphSet(), font.getBestCmap()
units = font['head'].unitsPerEm / 4
ranges = [(0xE050, 0xE06F), (0xE080, 0xE09F), (0xE0A0, 0xE0A5),
(0xE101, 0xE102), (0xE1E7, 0xE1E8), (0xE240, 0xE250),
(0xE260, 0xE270), (0xE4E0, 0xE4EE)]
records = []
for start, end in ranges:
for codepoint in range(start, end):
if codepoint not in cmap:
continue
pen = BoundsPen(glyphs)
glyphs[cmap[codepoint]].draw(pen)
if pen.bounds:
box = ', '.join(f'{v / units:.8f}F' for v in pen.bounds)
records.append(f' {{{codepoint}, {{{box}}}}},')
output.parent.mkdir(parents=True, exist_ok=True)
output.write_text('#pragma once\n#include <array>\n#include <cstdint>\nnamespace vamp_zero::font_data {\n'
'struct glyph { std::int32_t codepoint; std::array<float, 4> bounds; };\n'
f'inline constexpr std::array<glyph, {len(records)}> glyphs = {{{{\n'
+ '\n'.join(records) + '\n}};\n}\n', encoding='ascii')
if __name__ == '__main__':
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--font', type=Path, required=True)
parser.add_argument('--output', type=Path, required=True)
args = parser.parse_args()
generate(args.font, args.output)
+52
View File
@@ -0,0 +1,52 @@
#!/usr/bin/env python3
import argparse
import hashlib
from pathlib import Path
import platform
import subprocess
import tempfile
import urllib.request
VERSION = '4.7.4.260706075'
SHA256 = {
'x86_64': '9233ed1b87d3e6b45722278f3c286dcd41e83da778bd0f80a1dd04949696ad93',
'aarch64': '162ae55b317660f196b2e73d566bdb45c1e990ed4cc140709d25d97b9ef366b0',
}
def install(destination: Path) -> Path:
architecture = platform.machine()
if architecture not in SHA256:
raise RuntimeError('the pinned engraver requires an x86_64 or aarch64 Linux build host')
destination = destination.resolve()
executable = destination / 'squashfs-root' / 'AppRun'
marker = destination / 'sha256'
if executable.is_file() and marker.is_file() and marker.read_text().strip() == SHA256[architecture]:
return executable
if destination.exists() and any(destination.iterdir()):
raise RuntimeError(f'{destination} contains a different or incomplete installation; choose an empty directory')
destination.mkdir(parents=True, exist_ok=True)
name = f'MuseScore-Studio-{VERSION}-{architecture}.AppImage'
url = f'https://github.com/musescore/MuseScore/releases/download/v4.7.4/{name}'
with tempfile.TemporaryDirectory(prefix='vamp-musescore-download-') as temporary:
archive = Path(temporary) / name
digest = hashlib.sha256()
with urllib.request.urlopen(url, timeout=120) as response, archive.open('wb') as output:
while chunk := response.read(1024 * 1024):
digest.update(chunk)
output.write(chunk)
if digest.hexdigest() != SHA256[architecture]:
raise RuntimeError('MuseScore AppImage checksum mismatch')
archive.chmod(0o755)
subprocess.run([str(archive), '--appimage-extract'], cwd=destination, check=True, stdout=subprocess.DEVNULL)
if not executable.is_file():
raise RuntimeError('MuseScore AppImage does not contain AppRun')
marker.write_text(SHA256[architecture] + '\n')
return executable
def main() -> None:
parser = argparse.ArgumentParser(description='Install the pinned build-only MuseScore engraver without FUSE.')
parser.add_argument('destination', type=Path)
print(install(parser.parse_args().destination))
if __name__ == '__main__':
main()
-1
View File
@@ -1,3 +1,2 @@
Pillow==12.3.0
defusedxml==0.7.1
fonttools==4.63.0