@@ -1 +0,0 @@
|
||||
DisableFormat: true
|
||||
@@ -1,15 +0,0 @@
|
||||
CompileFlags:
|
||||
CompilationDatabase: build/build_x86_debug
|
||||
Add:
|
||||
- -Wall
|
||||
- -Wextra
|
||||
|
||||
Diagnostics:
|
||||
ClangTidy:
|
||||
Remove: ['*']
|
||||
---
|
||||
If:
|
||||
PathMatch: (include/vamp_pico/.*|src/vamp_pico/.*)
|
||||
|
||||
CompileFlags:
|
||||
CompilationDatabase: build/build_pico_debug
|
||||
@@ -74,6 +74,7 @@ jobs:
|
||||
libdrm-dev:arm64 \
|
||||
libegl-dev \
|
||||
libegl-dev:arm64 \
|
||||
libfribidi0 \
|
||||
libgbm-dev \
|
||||
libgbm-dev:arm64 \
|
||||
libgles-dev \
|
||||
@@ -87,7 +88,7 @@ jobs:
|
||||
python3 \
|
||||
python3-venv
|
||||
python3 -m venv build/build_common/ci_python
|
||||
build/build_common/ci_python/bin/python -m pip install --no-cache-dir conan==2.26.2
|
||||
build/build_common/ci_python/bin/python -m pip install --no-cache-dir conan==2.26.2 -r tools/requirements.txt
|
||||
echo "$PWD/build/build_common/ci_python/bin" >> "$GITHUB_PATH"
|
||||
- name: Restore Conan cache
|
||||
uses: actions/cache@v4
|
||||
@@ -101,6 +102,8 @@ jobs:
|
||||
run: python3 modulus.py build --target x86_64_gcc12_release
|
||||
- name: Test native release
|
||||
run: python3 modulus.py test --target x86_64_gcc12_release
|
||||
- name: Test asset generation
|
||||
run: python3 -m unittest tests.test_score_generator
|
||||
- name: Fetch Pico SDK
|
||||
if: ${{ gitea.event_name == 'workflow_dispatch' || (gitea.event_name == 'push' && gitea.ref == 'refs/heads/master') }}
|
||||
env:
|
||||
|
||||
+12
-9
@@ -1,4 +1,7 @@
|
||||
build/
|
||||
.clangd
|
||||
.clang-format
|
||||
pyrightconfig.json
|
||||
|
||||
**/__pycache__/
|
||||
*.pyc
|
||||
@@ -6,12 +9,12 @@ build/
|
||||
*.pyd
|
||||
*.log
|
||||
|
||||
package/CMakeCache.txt
|
||||
package/CMakeFiles/
|
||||
package/metadata/
|
||||
package/.ninja_*
|
||||
package/*.json
|
||||
package/*.cmake
|
||||
package/*.ninja
|
||||
package/*.sh
|
||||
package/*-smoke
|
||||
CMakeFiles/
|
||||
CMakeCache.txt
|
||||
CMakeUserPresets.json
|
||||
cmake_install.cmake
|
||||
CTestTestfile.cmake
|
||||
Testing/
|
||||
build.ninja
|
||||
.ninja_*
|
||||
compile_commands.json
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
set(CMAKE_HOST_SYSTEM "Linux-7.1.9-arch1-2")
|
||||
set(CMAKE_HOST_SYSTEM_NAME "Linux")
|
||||
set(CMAKE_HOST_SYSTEM_VERSION "7.1.9-arch1-2")
|
||||
set(CMAKE_HOST_SYSTEM_PROCESSOR "x86_64")
|
||||
|
||||
|
||||
|
||||
set(CMAKE_SYSTEM "Linux-7.1.9-arch1-2")
|
||||
set(CMAKE_SYSTEM_NAME "Linux")
|
||||
set(CMAKE_SYSTEM_VERSION "7.1.9-arch1-2")
|
||||
set(CMAKE_SYSTEM_PROCESSOR "x86_64")
|
||||
|
||||
set(CMAKE_CROSSCOMPILING "FALSE")
|
||||
|
||||
set(CMAKE_SYSTEM_LOADED 1)
|
||||
@@ -39,6 +39,8 @@ python3 modulus.py lsp
|
||||
|
||||
When running directly outside the generated Modulus Docker image, set `PICO_SDK_PATH` before refreshing the Pico database.
|
||||
|
||||
Editor settings live in `modulus.json` under `tooling.editor`. Modulus generates the ignored `.clangd`, `.clang-format`, and `pyrightconfig.json` files; edit the JSON settings rather than these outputs. The clangd configuration routes Zero/shared code to the native compile database and Pico code to its firmware database.
|
||||
|
||||
## Package
|
||||
|
||||
Product packaging targets Raspberry Pi OS/Debian trixie on ARM64 and optionally builds Pico firmware. Set `PICO_SDK_PATH` when building the firmware artifact:
|
||||
@@ -97,13 +99,18 @@ Authored score files use compact JSON. Metadata stays as normal JSON fields, whi
|
||||
|
||||
Notation tokens are `PITCH:DURATION`, `r:DURATION`, and `(PITCH PITCH ...):DURATION` for written chord tones. Durations use `1`, `2`, `4`, `8`, `16`, `32`, plus `.` for dotted values. `[Chord]` applies to the next token, `[(Chord)]` marks an optional turnaround chord that is used between generated performance iterations but omitted from the final ending, quoted text applies as a lyric to the previous note, `~` starts or ends ties, and `{N:M ...}` writes tuplets such as five quarter notes in the space of two quarter notes. A measure may also be an object with `notes` plus MusicXML-style metadata fields such as `attributes`, `directions`, `harmony`, or `barlines`.
|
||||
|
||||
Bundled third-party font assets live in `package/assets/fonts/petaluma`. Petaluma is from Steinberg and is distributed under the SIL Open Font License; the package keeps `OFL.txt` next to the font files. If the Pico bitmap font needs to be refreshed after changing the bundled UI font, run:
|
||||
Bundled fonts are OTF files in `package/assets/fonts/petaluma`: `Petaluma.otf` supplies music symbols and `PetalumaScript.otf` supplies text. Petaluma is from Steinberg under the SIL Open Font License. Runtime packages include these two fonts and `OFL.txt`; the upstream metadata is kept only as a source reference.
|
||||
|
||||
Font generation requires Pillow's Raqm layout support to preserve kerning. On Debian/Ubuntu, install `libfribidi0` alongside the pinned Python requirements. The build image and CI install both. See [Pillow's installation requirements](https://pillow.readthedocs.io/en/stable/installation/basic-installation.html).
|
||||
|
||||
Native and Pico builds generate their bitmap font implementation under `generated/vamp_style/font.cpp` in the build directory. The generated implementation is not checked in. The build image and CI install the pinned generator dependency automatically. For a direct build, first run:
|
||||
|
||||
```sh
|
||||
python3 tools/generate_pico_font.py
|
||||
python3 tools/generate_pico_font.py --check
|
||||
python3 -m pip install -r tools/requirements.txt
|
||||
```
|
||||
|
||||
To check a generated atlas, run `python3 tools/generate_pico_font.py --output build/build_x86_debug/generated/vamp_style/font.cpp --check`. Changing the source OTF or generator rebuilds the atlas automatically.
|
||||
|
||||
## License
|
||||
|
||||
Product Vamp is released under the MIT License. Bundled third-party fonts keep their own licenses next to the font files.
|
||||
|
||||
+3
-3
@@ -8,7 +8,7 @@ Product Vamp follows the Modulus product layout used by the khodo repos:
|
||||
- `include/vamp_pico` and `src/vamp_pico`: Pi Pico 2 W C++17 firmware.
|
||||
- `include/vamp_protocol` and `src/vamp_protocol`: shared route and page-command contracts used by both devices.
|
||||
- `cmake/pico.cmake` and `cmake/zero.cmake`: device-specific build definitions selected by the root `CMakeLists.txt`.
|
||||
- `include/vamp_style.hpp`, `include/vamp_style/font.hpp`, and `src/vamp_style`: shared color palette, Petaluma font paths, and Pico bitmap font data.
|
||||
- `include/vamp_style.hpp`, `include/vamp_style/font.hpp`, and `src/vamp_style.cpp`: shared color palette and Petaluma font interfaces. Bitmap font data is generated in the build directory.
|
||||
- `data`: authored source score JSON for performance songs and practice exercises.
|
||||
- `generator`: build-time Python preprocessing for performance arrangements and practice variants.
|
||||
- `package`: generic bundle inputs, scripts, config, static font assets, and device install files.
|
||||
@@ -52,7 +52,7 @@ The display is rotated 90 degrees clockwise into a 320x240 landscape UI. The top
|
||||
- Green: connected to the Zero API.
|
||||
|
||||
The body stays blank until a performance or practice score is active, then it shows the active title, selected part or active practice key, and page count. Touch controls are tap for next, double tap for previous, and tap-and-hold for select.
|
||||
The Pico text renderer uses an antialiased bitmap atlas generated from `package/assets/fonts/petaluma/PetalumaScript.otf`; regenerate it with `python3 tools/generate_pico_font.py` after font or atlas-size changes. The generated atlas includes ASCII kerning pairs so display text such as `VAMP` uses the same spacing as the source font.
|
||||
The Pico text renderer uses an antialiased bitmap atlas generated from `package/assets/fonts/petaluma/PetalumaScript.otf`. The shared font CMake rule generates `generated/vamp_style/font.cpp` separately in each native/Pico build directory, using `tools/generate_pico_font.py --output <path>`. Font and generator changes trigger regeneration. The generated atlas includes ASCII kerning pairs so display text such as `VAMP` uses the same spacing as the source font. The pinned Pillow build dependency is declared in `tools/requirements.txt`.
|
||||
|
||||
The root `CMakeLists.txt` is also the Pico firmware entrypoint when configured with `-DVAMP_PICO_FIRMWARE_PROJECT=ON`. That mode returns before the Zero/Linux targets are declared, so the Pico build can use the embedded ARM toolchain cleanly.
|
||||
|
||||
@@ -87,7 +87,7 @@ Luma owns the application shell and UI control tree. The score renderer uses Lum
|
||||
|
||||
## LSP
|
||||
|
||||
`.clangd` points native Zero and shared protocol code at `build/build_x86_debug`, and Pico code at `build/build_pico_debug`. Refresh both compile databases with:
|
||||
`tooling.editor.clangd` in `modulus.json` generates the ignored `.clangd`, pointing native Zero and shared protocol code at `build/build_x86_debug`, and Pico code at `build/build_pico_debug`. Refresh both compile databases with:
|
||||
|
||||
```sh
|
||||
python3 modulus.py lsp
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
find_package(Python3 COMPONENTS Interpreter REQUIRED)
|
||||
execute_process(
|
||||
COMMAND ${Python3_EXECUTABLE} -c "from PIL import features; assert features.check_feature('raqm')"
|
||||
RESULT_VARIABLE VAMP_PILLOW_STATUS
|
||||
ERROR_QUIET
|
||||
)
|
||||
if(NOT VAMP_PILLOW_STATUS EQUAL 0)
|
||||
message(FATAL_ERROR "Font generation requires Pillow with Raqm support. Install libfribidi0 on Debian/Ubuntu, then run: ${Python3_EXECUTABLE} -m pip install -r ${CMAKE_CURRENT_SOURCE_DIR}/tools/requirements.txt")
|
||||
endif()
|
||||
|
||||
set(VAMP_FONT_SOURCE ${CMAKE_CURRENT_BINARY_DIR}/generated/vamp_style/font.cpp)
|
||||
add_custom_command(
|
||||
OUTPUT ${VAMP_FONT_SOURCE}
|
||||
COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/tools/generate_pico_font.py
|
||||
--output ${VAMP_FONT_SOURCE}
|
||||
DEPENDS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tools/generate_pico_font.py
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tools/requirements.txt
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/package/assets/fonts/petaluma/PetalumaScript.otf
|
||||
VERBATIM
|
||||
)
|
||||
+2
-1
@@ -36,6 +36,7 @@ set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
pico_sdk_init()
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/font.cmake)
|
||||
|
||||
set(VAMP_MODULUS_INCLUDE_DIR "" CACHE PATH "Path to the Modulus public include directory")
|
||||
set(VAMP_RESOLVED_MODULUS_INCLUDE_DIR "${VAMP_MODULUS_INCLUDE_DIR}")
|
||||
@@ -75,7 +76,7 @@ endif()
|
||||
|
||||
add_executable(product-vamp-pico2w
|
||||
src/vamp_style.cpp
|
||||
src/vamp_style/font.cpp
|
||||
${VAMP_FONT_SOURCE}
|
||||
src/vamp_pico/display.cpp
|
||||
src/vamp_pico/http_client.cpp
|
||||
src/vamp_pico/main.cpp
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
option(VAMP_PICO_FIRMWARE_PROJECT "Configure this CMake invocation as the Pi Pico 2 W firmware project" OFF)
|
||||
option(VAMP_BUILD_PICO_FIRMWARE "Build the Pi Pico 2 W UF2 firmware artifact" OFF)
|
||||
option(VAMP_BUILD_ZERO_IMAGE "Build the Pi Zero 2 W Docker image archive artifact" OFF)
|
||||
option(BUILD_TESTING "Build Product Vamp tests" OFF)
|
||||
|
||||
set(VAMP_PICO_SDK_VERSION "2.3.0" CACHE STRING "Raspberry Pi Pico SDK git tag used when fetching the SDK")
|
||||
set(VAMP_PICO_WIFI_SSID "Vamp Control" CACHE STRING "Default Pico Wi-Fi SSID")
|
||||
|
||||
+7
-3
@@ -1,4 +1,5 @@
|
||||
include(GNUInstallDirs)
|
||||
option(BUILD_TESTING "Build Product Vamp tests" OFF)
|
||||
include(CTest)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
@@ -11,7 +12,7 @@ find_package(ligo CONFIG REQUIRED)
|
||||
find_package(noto CONFIG REQUIRED)
|
||||
find_package(luma CONFIG REQUIRED)
|
||||
find_package(sonus CONFIG REQUIRED)
|
||||
find_package(Python3 COMPONENTS Interpreter REQUIRED)
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/font.cmake)
|
||||
|
||||
execute_process(
|
||||
COMMAND git rev-parse --short=12 HEAD
|
||||
@@ -26,7 +27,7 @@ endif()
|
||||
|
||||
set(VAMP_STYLE_SOURCES
|
||||
src/vamp_style.cpp
|
||||
src/vamp_style/font.cpp
|
||||
${VAMP_FONT_SOURCE}
|
||||
)
|
||||
|
||||
add_library(vamp-style STATIC ${VAMP_STYLE_SOURCES})
|
||||
@@ -186,6 +187,10 @@ if(VAMP_BUILD_PICO_FIRMWARE)
|
||||
file(GLOB VAMP_PICO_SOURCES CONFIGURE_DEPENDS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/cmake/pico.cmake
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/cmake/font.cmake
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tools/generate_pico_font.py
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tools/requirements.txt
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/package/assets/fonts/petaluma/PetalumaScript.otf
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/cmake/vamp_options.cmake
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/*.hpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/vamp_style/*.hpp
|
||||
@@ -194,7 +199,6 @@ if(VAMP_BUILD_PICO_FIRMWARE)
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/vamp_pico/*.hpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/vamp_protocol/*.hpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/vamp_style.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/vamp_style/*.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/vamp_pico/*.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/vamp_protocol/*.cpp
|
||||
)
|
||||
|
||||
+3
-1
@@ -43,13 +43,15 @@ class product_vamp_conan(conan.ConanFile):
|
||||
"package/scripts/*.sh",
|
||||
"package/zero/*",
|
||||
"src/vamp_style.cpp",
|
||||
"src/vamp_style/*.cpp",
|
||||
"src/vamp_pico/*.cpp",
|
||||
"src/vamp_protocol/*.cpp",
|
||||
"src/vamp_zero/*.cpp",
|
||||
"tests/CMakeLists.txt",
|
||||
"tests/*.cpp",
|
||||
"tests/*.hpp",
|
||||
"tests/*.py",
|
||||
"tools/*.py",
|
||||
"tools/requirements.txt",
|
||||
)
|
||||
|
||||
def requirements(self):
|
||||
|
||||
+11
-3
@@ -9,6 +9,16 @@ from generator.practice.generate import generate_practice_scores
|
||||
from generator.score import count_json_files, validate_generated_tree
|
||||
from generator.summary import validate_expected_performance_summary, validate_practice_variants
|
||||
|
||||
RUNTIME_FONT_FILES = ("Petaluma.otf", "PetalumaScript.otf", "OFL.txt")
|
||||
|
||||
|
||||
def copy_runtime_fonts(static_assets_dir: Path, output_dir: Path) -> None:
|
||||
source = static_assets_dir / "fonts" / "petaluma"
|
||||
destination = output_dir / "fonts" / "petaluma"
|
||||
destination.mkdir(parents=True, exist_ok=True)
|
||||
for name in RUNTIME_FONT_FILES:
|
||||
shutil.copy2(source / name, destination / name)
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(description="Generate Product Vamp package score assets.")
|
||||
@@ -30,9 +40,7 @@ def main() -> int:
|
||||
shutil.rmtree(output_dir)
|
||||
output_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
fonts_src = static_assets_dir / "fonts"
|
||||
if fonts_src.exists():
|
||||
shutil.copytree(fonts_src, output_dir / "fonts", dirs_exist_ok=True)
|
||||
copy_runtime_fonts(static_assets_dir, output_dir)
|
||||
|
||||
performance_count = generate_performance_scores(data_dir / "songs", output_dir / "songs")
|
||||
practice_count = generate_practice_scores(data_dir / "practice", output_dir / "practice")
|
||||
|
||||
@@ -20,6 +20,28 @@
|
||||
"name": "product-vamp"
|
||||
},
|
||||
"tooling": {
|
||||
"editor": {
|
||||
"clangd": [
|
||||
{
|
||||
"CompileFlags": {
|
||||
"CompilationDatabase": "build/build_x86_debug",
|
||||
"Add": ["-Wall", "-Wextra"]
|
||||
},
|
||||
"Diagnostics": {"ClangTidy": {"Remove": ["*"]}}
|
||||
},
|
||||
{
|
||||
"If": {"PathMatch": "(include/vamp_pico/.*|src/vamp_pico/.*)"},
|
||||
"CompileFlags": {"CompilationDatabase": "build/build_pico_debug"}
|
||||
}
|
||||
],
|
||||
"pyright": {
|
||||
"include": ["modulus.py", "conanfile.py", "generator", "tools", "tests", "build/build_tools"],
|
||||
"extraPaths": ["build/build_common/modulus", "."],
|
||||
"typeCheckingMode": "off",
|
||||
"reportMissingImports": false,
|
||||
"reportMissingModuleSource": false
|
||||
}
|
||||
},
|
||||
"default_target": "x86_64_gcc12_debug",
|
||||
"docker": {
|
||||
"image": "product-vamp-modulus-build:dev"
|
||||
|
||||
+4
-1
@@ -164,6 +164,7 @@ RUN apt-get update \\
|
||||
libdrm-dev:arm64 \\
|
||||
libegl-dev \\
|
||||
libegl-dev:arm64 \\
|
||||
libfribidi0 \\
|
||||
libgbm-dev \\
|
||||
libgbm-dev:arm64 \\
|
||||
libgles-dev \\
|
||||
@@ -196,8 +197,10 @@ RUN python3 -m venv /opt/modulus-python
|
||||
|
||||
ENV PATH=/opt/modulus-python/bin:$PATH
|
||||
|
||||
COPY tools/requirements.txt /tmp/vamp-build-requirements.txt
|
||||
|
||||
RUN python -m pip install --no-cache-dir \\
|
||||
conan=={CONAN_VERSION}
|
||||
conan=={CONAN_VERSION} -r /tmp/vamp-build-requirements.txt
|
||||
|
||||
WORKDIR /workspace
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -1,14 +0,0 @@
|
||||
{
|
||||
"include": [
|
||||
"modulus.py",
|
||||
"package/conanfile.py",
|
||||
"build/build_tools"
|
||||
],
|
||||
"extraPaths": [
|
||||
"build/build_common/modulus",
|
||||
"."
|
||||
],
|
||||
"typeCheckingMode": "off",
|
||||
"reportMissingImports": false,
|
||||
"reportMissingModuleSource": false
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,12 +1,47 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
import unittest.mock
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
|
||||
from generator.__main__ import copy_runtime_fonts
|
||||
from generator.arrange.generate import arrange_document
|
||||
from generator.arrange.fretboard import chord_pitch_classes, pitches_for_voicing
|
||||
from generator.styles import BUILT_IN_STYLES
|
||||
from generator.transposition import mod12
|
||||
from generator.score import normalize_score_document
|
||||
from tools import generate_pico_font
|
||||
|
||||
|
||||
class FontAssetsTests(unittest.TestCase):
|
||||
def test_font_generator_requires_kerning_backend(self):
|
||||
with unittest.mock.patch.object(generate_pico_font.features, "check_feature", return_value=False):
|
||||
with self.assertRaisesRegex(RuntimeError, "Raqm"):
|
||||
generate_pico_font.generate()
|
||||
|
||||
def test_runtime_fonts_exclude_unused_assets(self):
|
||||
root = Path(__file__).resolve().parents[1]
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
output = Path(directory)
|
||||
copy_runtime_fonts(root / "package/assets", output)
|
||||
files = {path.name for path in (output / "fonts/petaluma").iterdir()}
|
||||
self.assertEqual(files, {"Petaluma.otf", "PetalumaScript.otf", "OFL.txt"})
|
||||
|
||||
def test_font_generator_uses_explicit_build_output(self):
|
||||
root = Path(__file__).resolve().parents[1]
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
output = Path(directory) / "generated/font.cpp"
|
||||
command = [sys.executable, str(root / "tools/generate_pico_font.py"), "--output", str(output)]
|
||||
subprocess.run(command, check=True, capture_output=True, text=True)
|
||||
self.assertNotIn("std::array<pair_adjustment, 0>", output.read_text(encoding="utf-8"))
|
||||
before = output.stat().st_mtime_ns
|
||||
subprocess.run([*command, "--check"], check=True, capture_output=True, text=True)
|
||||
self.assertEqual(before, output.stat().st_mtime_ns)
|
||||
output.write_text("stale", encoding="utf-8")
|
||||
self.assertNotEqual(subprocess.run([*command, "--check"], capture_output=True).returncode, 0)
|
||||
|
||||
|
||||
class CompactScoreJsonTests(unittest.TestCase):
|
||||
|
||||
@@ -4,12 +4,11 @@ import argparse
|
||||
import difflib
|
||||
from pathlib import Path
|
||||
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
from PIL import Image, ImageDraw, ImageFont, features
|
||||
|
||||
|
||||
REPO = Path(__file__).resolve().parents[1]
|
||||
FONT_PATH = REPO / "package/assets/fonts/petaluma/PetalumaScript.otf"
|
||||
OUTPUT_PATH = REPO / "src/vamp_style/font.cpp"
|
||||
FONT_SIZE = 32
|
||||
FONT_HEIGHT = 36
|
||||
FONT_MAX_WIDTH = 28
|
||||
@@ -63,7 +62,9 @@ def pair_adjustments(font: ImageFont.FreeTypeFont) -> list[tuple[int, int]]:
|
||||
|
||||
|
||||
def generate() -> str:
|
||||
font = ImageFont.truetype(str(FONT_PATH), FONT_SIZE)
|
||||
if not features.check_feature("raqm"):
|
||||
raise RuntimeError("Font generation requires Pillow with Raqm support; install libfribidi0 on Debian/Ubuntu.")
|
||||
font = ImageFont.truetype(str(FONT_PATH), FONT_SIZE, layout_engine=ImageFont.Layout.RAQM)
|
||||
min_top = min(font.getbbox(chr(value))[1] for value in range(FIRST_CODEPOINT, LAST_CODEPOINT + 1))
|
||||
y_offset = max(0, -min_top)
|
||||
adjustments = pair_adjustments(font)
|
||||
@@ -173,27 +174,31 @@ def generate() -> str:
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--output", type=Path, required=True)
|
||||
parser.add_argument("--check", action="store_true")
|
||||
args = parser.parse_args()
|
||||
|
||||
generated = generate()
|
||||
if args.check:
|
||||
current = OUTPUT_PATH.read_text()
|
||||
if not args.output.is_file():
|
||||
parser.error(f"generated font is missing: {args.output}")
|
||||
current = args.output.read_text(encoding="utf-8")
|
||||
if current == generated:
|
||||
print("pico font is up to date")
|
||||
return 0
|
||||
diff = difflib.unified_diff(
|
||||
current.splitlines(),
|
||||
generated.splitlines(),
|
||||
fromfile=str(OUTPUT_PATH),
|
||||
tofile=f"{OUTPUT_PATH} (generated)",
|
||||
fromfile=str(args.output),
|
||||
tofile=f"{args.output} (generated)",
|
||||
lineterm="",
|
||||
)
|
||||
print("\n".join(diff))
|
||||
return 1
|
||||
|
||||
OUTPUT_PATH.write_text(generated)
|
||||
print(f"generated {OUTPUT_PATH}")
|
||||
args.output.parent.mkdir(parents=True, exist_ok=True)
|
||||
args.output.write_text(generated, encoding="utf-8")
|
||||
print(f"generated {args.output}")
|
||||
return 0
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
Pillow==12.3.0
|
||||
Reference in New Issue
Block a user