Editor
ci / checks (push) Has been cancelled

This commit is contained in:
khodowany
2026-09-10 18:54:24 -05:00
parent 1a13d6b0e1
commit ea4e0bbba1
22 changed files with 148 additions and 6189 deletions
-1
View File
@@ -1 +0,0 @@
DisableFormat: true
-15
View File
@@ -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
+4 -1
View File
@@ -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
View File
@@ -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
-15
View File
@@ -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)
+10 -3
View File
@@ -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
View File
@@ -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
+21
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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")
+22
View File
@@ -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
View File
@@ -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.
-14
View File
@@ -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
+35
View File
@@ -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):
+13 -8
View File
@@ -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
+1
View File
@@ -0,0 +1 @@
Pillow==12.3.0