riffpi 0.2.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- riffpi-0.2.4/.github/FUNDING.yml +15 -0
- riffpi-0.2.4/.github/workflows/docs.yml +32 -0
- riffpi-0.2.4/.github/workflows/lint-and-build.yml +33 -0
- riffpi-0.2.4/.github/workflows/release.yml +50 -0
- riffpi-0.2.4/.github/workflows/tag-release.yml +19 -0
- riffpi-0.2.4/.gitignore +14 -0
- riffpi-0.2.4/.python-version +1 -0
- riffpi-0.2.4/CLAUDE.md +156 -0
- riffpi-0.2.4/LICENSE.md +313 -0
- riffpi-0.2.4/PKG-INFO +96 -0
- riffpi-0.2.4/README.md +72 -0
- riffpi-0.2.4/cern_ohl_w_v2_howto.pdf +0 -0
- riffpi-0.2.4/combined_test.py +236 -0
- riffpi-0.2.4/docs/architecture.md +114 -0
- riffpi-0.2.4/docs/images/img1.jpg +0 -0
- riffpi-0.2.4/docs/images/img2.jpg +0 -0
- riffpi-0.2.4/docs/images/img3.jpg +0 -0
- riffpi-0.2.4/docs/images/pcb-bottom.svg +10958 -0
- riffpi-0.2.4/docs/images/pcb-top.svg +27366 -0
- riffpi-0.2.4/docs/images/schematic.svg +67373 -0
- riffpi-0.2.4/docs/index.md +33 -0
- riffpi-0.2.4/docs/installation.md +161 -0
- riffpi-0.2.4/docs/usage.md +78 -0
- riffpi-0.2.4/joystick_as_mouse_test.py +178 -0
- riffpi-0.2.4/joystick_test.py +46 -0
- riffpi-0.2.4/keypad_int_test.py +68 -0
- riffpi-0.2.4/keypad_test.py +50 -0
- riffpi-0.2.4/kicad_board/.gitignore +60 -0
- riffpi-0.2.4/kicad_board/.kinotes/KiNotes_kicad_board.md +27 -0
- riffpi-0.2.4/kicad_board/.kinotes/backups/20260406_105647_todos.json +44 -0
- riffpi-0.2.4/kicad_board/.kinotes/backups/20260406_105648_todos.json +44 -0
- riffpi-0.2.4/kicad_board/.kinotes/backups/20260406_105649_todos.json +44 -0
- riffpi-0.2.4/kicad_board/.kinotes/backups/20260406_105650_todos.json +44 -0
- riffpi-0.2.4/kicad_board/.kinotes/backups/20260406_105651_todos.json +44 -0
- riffpi-0.2.4/kicad_board/.kinotes/backups/20260406_105652_todos.json +44 -0
- riffpi-0.2.4/kicad_board/.kinotes/backups/20260406_105653_todos.json +44 -0
- riffpi-0.2.4/kicad_board/.kinotes/backups/20260406_105703_todos.json +44 -0
- riffpi-0.2.4/kicad_board/.kinotes/backups/20260406_105703_version_log.json +4 -0
- riffpi-0.2.4/kicad_board/.kinotes/backups/20260406_105712_KiNotes_kicad_board.md +26 -0
- riffpi-0.2.4/kicad_board/.kinotes/backups/20260406_105712_settings.json +59 -0
- riffpi-0.2.4/kicad_board/.kinotes/backups/20260406_105712_todos.json +44 -0
- riffpi-0.2.4/kicad_board/.kinotes/backups/20260406_105712_version_log.json +4 -0
- riffpi-0.2.4/kicad_board/.kinotes/backups/20260406_105715_version_log.json +4 -0
- riffpi-0.2.4/kicad_board/.kinotes/backups/20260406_105721_KiNotes_kicad_board.md +27 -0
- riffpi-0.2.4/kicad_board/.kinotes/backups/20260406_105721_settings.json +59 -0
- riffpi-0.2.4/kicad_board/.kinotes/backups/20260406_105721_todos.json +44 -0
- riffpi-0.2.4/kicad_board/.kinotes/backups/20260406_105721_version_log.json +4 -0
- riffpi-0.2.4/kicad_board/.kinotes/multieff_worklog_20260406.md +2 -0
- riffpi-0.2.4/kicad_board/.kinotes/settings.json +59 -0
- riffpi-0.2.4/kicad_board/.kinotes/todos.json +44 -0
- riffpi-0.2.4/kicad_board/.kinotes/version_log.json +4 -0
- riffpi-0.2.4/kicad_board/fabrication-toolkit-options.json +1 -0
- riffpi-0.2.4/kicad_board/multieff.kicad_dru +133 -0
- riffpi-0.2.4/kicad_board/multieff.kicad_pcb +20692 -0
- riffpi-0.2.4/kicad_board/multieff.kicad_prl +130 -0
- riffpi-0.2.4/kicad_board/multieff.kicad_pro +645 -0
- riffpi-0.2.4/kicad_board/multieff.kicad_sch +12336 -0
- riffpi-0.2.4/kicad_board/multieff.rules +84 -0
- riffpi-0.2.4/leds_int_test.py +106 -0
- riffpi-0.2.4/leds_test.py +69 -0
- riffpi-0.2.4/mkdocs.yml +24 -0
- riffpi-0.2.4/multieffect_int.py +237 -0
- riffpi-0.2.4/pyproject.toml +65 -0
- riffpi-0.2.4/rotary_encoder_int.py +225 -0
- riffpi-0.2.4/rotary_encoder_int_test.py +67 -0
- riffpi-0.2.4/rotary_encoder_test.py +66 -0
- riffpi-0.2.4/rotary_encoders_int_test.py +112 -0
- riffpi-0.2.4/rotary_encoders_test.py +57 -0
- riffpi-0.2.4/src/riffpi/__init__.py +3 -0
- riffpi-0.2.4/src/riffpi/cli.py +33 -0
- riffpi-0.2.4/src/riffpi/daemon.py +246 -0
- riffpi-0.2.4/src/riffpi/expression_pedal.py +88 -0
- riffpi-0.2.4/src/riffpi/joystick.py +198 -0
- riffpi-0.2.4/src/riffpi/keypad.py +169 -0
- riffpi-0.2.4/src/riffpi/mcp_button.py +27 -0
- riffpi-0.2.4/src/riffpi/mcp_led.py +22 -0
- riffpi-0.2.4/src/riffpi/rotary_encoder.py +168 -0
- riffpi-0.2.4/src/riffpi/service.py +92 -0
- riffpi-0.2.4/test_int.py +190 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# These are supported funding model platforms
|
|
2
|
+
|
|
3
|
+
github: kleag# Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
|
4
|
+
patreon: # Replace with a single Patreon username
|
|
5
|
+
open_collective: # Replace with a single Open Collective username
|
|
6
|
+
ko_fi: # Replace with a single Ko-fi username
|
|
7
|
+
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
|
8
|
+
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
|
9
|
+
liberapay: # Replace with a single Liberapay username
|
|
10
|
+
issuehunt: # Replace with a single IssueHunt username
|
|
11
|
+
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
|
|
12
|
+
polar: # Replace with a single Polar username
|
|
13
|
+
buy_me_a_coffee: kleag# Replace with a single Buy Me a Coffee username
|
|
14
|
+
thanks_dev: # Replace with a single thanks.dev username
|
|
15
|
+
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
name: docs
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
paths:
|
|
8
|
+
- "docs/**"
|
|
9
|
+
- "mkdocs.yml"
|
|
10
|
+
- "README.md"
|
|
11
|
+
- ".github/workflows/docs.yml"
|
|
12
|
+
|
|
13
|
+
permissions:
|
|
14
|
+
contents: write
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
deploy:
|
|
18
|
+
runs-on: ubuntu-latest
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@v4
|
|
21
|
+
|
|
22
|
+
- name: Configure Git Credentials
|
|
23
|
+
run: |
|
|
24
|
+
git config user.name github-actions[bot]
|
|
25
|
+
git config user.email 41898282+github-actions[bot]@users.noreply.github.com
|
|
26
|
+
|
|
27
|
+
- uses: actions/setup-python@v5
|
|
28
|
+
with:
|
|
29
|
+
python-version: "3.x"
|
|
30
|
+
|
|
31
|
+
- run: pip install mkdocs-material
|
|
32
|
+
- run: mkdocs gh-deploy --force
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
name: lint-and-build
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
pull_request:
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
lint-and-build:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v4
|
|
14
|
+
|
|
15
|
+
- uses: actions/setup-python@v5
|
|
16
|
+
with:
|
|
17
|
+
python-version: "3.11"
|
|
18
|
+
|
|
19
|
+
- name: Install dev tooling
|
|
20
|
+
run: pip install ruff build twine
|
|
21
|
+
|
|
22
|
+
# Note: the package's runtime dependencies (Adafruit Blinka, gpiozero, ...) actively
|
|
23
|
+
# probe for real Raspberry Pi hardware on import, so they cannot be installed/imported
|
|
24
|
+
# on a generic GitHub-hosted runner. This job only lints and validates packaging, it
|
|
25
|
+
# does not import riffpi itself.
|
|
26
|
+
- name: Lint
|
|
27
|
+
run: ruff check src/
|
|
28
|
+
|
|
29
|
+
- name: Build sdist and wheel
|
|
30
|
+
run: python -m build
|
|
31
|
+
|
|
32
|
+
- name: Check package metadata
|
|
33
|
+
run: twine check dist/*
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
name: release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
# Not `release: published`: tag-release.yml creates that release using the default
|
|
5
|
+
# GITHUB_TOKEN, and GitHub's anti-recursion rule means events created via GITHUB_TOKEN
|
|
6
|
+
# don't trigger other workflows. workflow_run isn't subject to that restriction, so we
|
|
7
|
+
# chain off tag-release.yml's completion instead.
|
|
8
|
+
workflow_run:
|
|
9
|
+
workflows: ["tag-release"]
|
|
10
|
+
types: [completed]
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
build:
|
|
14
|
+
if: github.event.workflow_run.conclusion == 'success'
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v4
|
|
18
|
+
with:
|
|
19
|
+
ref: ${{ github.event.workflow_run.head_sha }}
|
|
20
|
+
|
|
21
|
+
- uses: actions/setup-python@v5
|
|
22
|
+
with:
|
|
23
|
+
python-version: "3.11"
|
|
24
|
+
|
|
25
|
+
- name: Install build tooling
|
|
26
|
+
run: pip install build
|
|
27
|
+
|
|
28
|
+
- name: Build sdist and wheel
|
|
29
|
+
run: python -m build
|
|
30
|
+
|
|
31
|
+
- uses: actions/upload-artifact@v4
|
|
32
|
+
with:
|
|
33
|
+
name: dist
|
|
34
|
+
path: dist/
|
|
35
|
+
|
|
36
|
+
publish:
|
|
37
|
+
needs: build
|
|
38
|
+
runs-on: ubuntu-latest
|
|
39
|
+
environment: pypi
|
|
40
|
+
permissions:
|
|
41
|
+
# Required for PyPI Trusted Publishing (OIDC) - no API token stored in this repo.
|
|
42
|
+
id-token: write
|
|
43
|
+
steps:
|
|
44
|
+
- uses: actions/download-artifact@v4
|
|
45
|
+
with:
|
|
46
|
+
name: dist
|
|
47
|
+
path: dist/
|
|
48
|
+
|
|
49
|
+
- name: Publish to PyPI
|
|
50
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
name: tag-release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "*.*.*"
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
create-release:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
permissions:
|
|
12
|
+
contents: write
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
|
+
|
|
16
|
+
- name: Create GitHub Release
|
|
17
|
+
env:
|
|
18
|
+
GH_TOKEN: ${{ github.token }}
|
|
19
|
+
run: gh release create "${{ github.ref_name }}" --title "${{ github.ref_name }}" --generate-notes
|
riffpi-0.2.4/.gitignore
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.11
|
riffpi-0.2.4/CLAUDE.md
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Project overview
|
|
6
|
+
|
|
7
|
+
RiffPi (PyPI/import name `riffpi`; the GitHub repo is `kleag/riffpi`, formerly `kleag/kleagmfx`)
|
|
8
|
+
is a DIY guitar
|
|
9
|
+
multi-effect foot controller built around a Raspberry Pi 5 + Pisound sound card, running Guitarix
|
|
10
|
+
as the effects engine. This repo holds:
|
|
11
|
+
|
|
12
|
+
- `src/riffpi/`: the installable Python package — the control daemon that reads the physical
|
|
13
|
+
controls (foot switches, rotary encoders, keypad, joystick, expression pedal) and drives
|
|
14
|
+
Guitarix over a virtual MIDI port.
|
|
15
|
+
- Root-level `*_test.py` / `*_int.py` files: standalone manual/legacy hardware scripts, **not**
|
|
16
|
+
part of the installed package (see Testing and Architecture below).
|
|
17
|
+
- KiCad hardware design files for the controller PCB (`kicad_board/`).
|
|
18
|
+
- MkDocs documentation source (`docs/`), published to GitHub Pages.
|
|
19
|
+
|
|
20
|
+
The hardware talks to the Pi over I2C: two MCP23017 GPIO expanders (`0x20`, `0x21`) for buttons/
|
|
21
|
+
LEDs/encoders/keypad, and an ADS1115 ADC for the analog joystick and expression pedal. Full
|
|
22
|
+
wiring/pin maps live in `docs/architecture.md`; Raspberry Pi OS setup (I2C enablement, `uinput`
|
|
23
|
+
permissions, systemd service, etc.) is in `docs/installation.md`.
|
|
24
|
+
|
|
25
|
+
## Environment & running
|
|
26
|
+
|
|
27
|
+
- Python >=3.11, packaged with `hatchling` (`[build-system]` in `pyproject.toml`). Build with
|
|
28
|
+
`python -m build` or `uv build`; install locally with `pip install -e .`.
|
|
29
|
+
- Hardware-dependent libraries (`board`, `busio`, `digitalio`, `adafruit_*`, `gpiozero`, `uinput`,
|
|
30
|
+
...) only work on an actual Raspberry Pi with I2C enabled and the user in the `input` group.
|
|
31
|
+
**None of this code can be run or imported on a non-Pi dev machine** — Blinka (`board`/`busio`)
|
|
32
|
+
actively probes for real hardware on import and raises if it doesn't find a supported board.
|
|
33
|
+
Reason about the package by reading; verify changes with `python -m py_compile` and `ruff
|
|
34
|
+
check src/`, not by importing/running it.
|
|
35
|
+
- Entry point: the `riffpi` console script (`riffpi.cli:main`, installed via
|
|
36
|
+
`[project.scripts]`), an argparse dispatcher over three subcommands — `run` (default when no
|
|
37
|
+
subcommand is given), `install-service`, `uninstall-service`. `riffpi run` calls
|
|
38
|
+
`riffpi.daemon.run()`, which opens a virtual ALSA/JACK MIDI port named `KleagMFX` via `mido`,
|
|
39
|
+
links it to Guitarix (`gx_head_amp`) through PipeWire (`pw-link`), then spawns one thread per
|
|
40
|
+
input device (buttons, joystick, keypad, expression pedal, each rotary encoder) plus a
|
|
41
|
+
MIDI-input listener thread that keeps LED/encoder state in sync when Guitarix itself changes a
|
|
42
|
+
CC value.
|
|
43
|
+
- `riffpi install-service` / `riffpi uninstall-service` (implemented in `riffpi/service.py`)
|
|
44
|
+
write/remove `~/.config/systemd/user/riffpi.service` and enable/disable it via `systemctl
|
|
45
|
+
--user`. `pip install` never does this on its own — it's a deliberate, separate opt-in step;
|
|
46
|
+
don't wire service installation into packaging/install hooks. See `docs/installation.md` for
|
|
47
|
+
the full flow and PipeWire/udev/wifi power-management setup.
|
|
48
|
+
|
|
49
|
+
## Testing
|
|
50
|
+
|
|
51
|
+
There is no pytest/unittest suite. Root-level files named `*_test.py` (and `test_int.py`) are
|
|
52
|
+
standalone manual exercise scripts for a single piece of hardware — run directly on the Pi
|
|
53
|
+
(`python3 rotary_encoder_test.py`) with real hardware attached, and verified by watching printed
|
|
54
|
+
output / physical LEDs, not by assertions. They are **not** part of the `src/riffpi` package and
|
|
55
|
+
aren't shipped in the wheel/sdist. When changing a driver module, prefer updating or running its
|
|
56
|
+
matching `*_test.py` script over trying to add automated tests.
|
|
57
|
+
|
|
58
|
+
CI (`.github/workflows/lint-and-build.yml`) runs `ruff check src/` plus `python -m build` +
|
|
59
|
+
`twine check dist/*` on every push/PR — lint and packaging validation only. It cannot actually
|
|
60
|
+
import or run `riffpi` (see the Blinka caveat above), so this is the practical ceiling for
|
|
61
|
+
automated verification without a self-hosted Pi runner.
|
|
62
|
+
|
|
63
|
+
## Docs site & release
|
|
64
|
+
|
|
65
|
+
- `docs/` is an MkDocs (Material theme) site, configured by `mkdocs.yml`.
|
|
66
|
+
`.github/workflows/docs.yml` runs `mkdocs gh-deploy --force`, but only on pushes to `main` that
|
|
67
|
+
touch `docs/`, `mkdocs.yml`, or `README.md`.
|
|
68
|
+
- `.github/workflows/release.yml` builds and publishes to PyPI via Trusted Publishing (OIDC) —
|
|
69
|
+
no stored token. Requires the `riffpi` PyPI project to have this repo registered as a trusted
|
|
70
|
+
publisher (a one-time manual step on pypi.org, done as a "pending publisher" before the
|
|
71
|
+
project existed — PyPI creates the project on the first successful publish).
|
|
72
|
+
- Version bumps use `bumpver` (`[tool.bumpver]` in `pyproject.toml`), which commits, tags
|
|
73
|
+
(bare `MAJOR.MINOR.PATCH`, no `v` prefix), and pushes — it does **not** create a GitHub
|
|
74
|
+
Release itself. `.github/workflows/tag-release.yml` watches for those tag pushes and runs
|
|
75
|
+
`gh release create` (using the default `GITHUB_TOKEN`) to publish a GitHub Release from the
|
|
76
|
+
tag. `release.yml` is triggered off `workflow_run: tag-release` completing, **not**
|
|
77
|
+
`release: published` — a release created via `GITHUB_TOKEN` doesn't fire other event
|
|
78
|
+
triggers (GitHub's anti-recursion rule), so chaining on `release: published` silently never
|
|
79
|
+
ran. `release.yml`'s `build` job checks out `github.event.workflow_run.head_sha` to build the
|
|
80
|
+
tagged commit. Full chain: `bumpver update` → tag pushed → `tag-release.yml` creates the
|
|
81
|
+
GitHub Release → its completion triggers `release.yml` → builds and publishes to PyPI.
|
|
82
|
+
|
|
83
|
+
## Code architecture
|
|
84
|
+
|
|
85
|
+
### Two parallel implementations per device: package vs. root-level register-level scripts
|
|
86
|
+
|
|
87
|
+
Most physical inputs have **two independent implementations**:
|
|
88
|
+
|
|
89
|
+
- The production version, in `src/riffpi/` (imported by `riffpi.daemon`), built on the Adafruit
|
|
90
|
+
CircuitPython stack (`adafruit_mcp230xx`, `digitalio.Direction`/`Pull`, `busio.I2C`) —
|
|
91
|
+
`rotary_encoder.py`, `keypad.py`, `joystick.py`, `expression_pedal.py`, `mcp_button.py`,
|
|
92
|
+
`mcp_led.py`.
|
|
93
|
+
- Root-level `*_int.py` scripts (e.g. `rotary_encoder_int.py`, `multieffect_int.py`,
|
|
94
|
+
`test_int.py`) that talk to the MCP23017 directly over `smbus2`/`lgpio` register writes and use
|
|
95
|
+
hardware interrupts (`GPINTEN`, `lgpio.callback` on falling edges) instead of polling. These are
|
|
96
|
+
an alternate/experimental lower-latency approach, not wired into the main daemon and not part
|
|
97
|
+
of the installed package.
|
|
98
|
+
|
|
99
|
+
When asked to fix or extend a device driver, check whether the change belongs in the
|
|
100
|
+
`src/riffpi/` version, the root-level `_int` register-level version, or both — they duplicate
|
|
101
|
+
logic independently and are **not** kept in sync automatically.
|
|
102
|
+
|
|
103
|
+
### Control flow in `riffpi/daemon.py`
|
|
104
|
+
|
|
105
|
+
- `main()` does all hardware/MIDI init (previously module-level code in the pre-packaging
|
|
106
|
+
`multieffect.py`) then spawns the worker threads; module-level functions (`handle_effect_toggle`,
|
|
107
|
+
`midi_input_thread`, `buttons_thread`, `main_thread_loop`, `send_cc`, ...) reach the objects
|
|
108
|
+
`main()` creates (`midi_out`, `midi_in`, `buttons`, `leds`, `encoders`, `task_queue`,
|
|
109
|
+
`PRESET_ENCODER_INDEX`) via `global`, matching the module's original flat-script style rather
|
|
110
|
+
than passing them around explicitly — keep that pattern if you touch this file rather than
|
|
111
|
+
introducing a class/config-object refactor.
|
|
112
|
+
- Global state: `effect_states` (bool per foot switch + one slot per encoder's button) and
|
|
113
|
+
`current_preset_bank` are shared across threads with no lock beyond the implicit GIL for simple
|
|
114
|
+
list/int mutation; the one place true cross-thread coordination happens is `task_queue`
|
|
115
|
+
(a `queue.Queue` drained by `main_thread_loop`, currently only used for the `"reset"` action
|
|
116
|
+
queued from `keypad.py`).
|
|
117
|
+
- `i2c_lock` (a `threading.Lock`) guards ADS1115 reads shared between `Joystick` and
|
|
118
|
+
`ExpressionPedal`, since both poll the same `ads` instance from different threads.
|
|
119
|
+
- Foot switch buttons and each `RotaryEncoder`'s built-in push button all route through the same
|
|
120
|
+
`handle_effect_toggle(idx)` callback, where `idx` is the position in the `buttons` list
|
|
121
|
+
(`[4 foot switches] + [4 encoder buttons]`, in that order). `PRESET_ENCODER_INDEX` is computed
|
|
122
|
+
in `main()` as the buttons-list position of the **last encoder's** button (not a hardcoded
|
|
123
|
+
literal — it was hardcoded to `3` at one point, which actually pointed at the 4th foot switch
|
|
124
|
+
instead; don't reintroduce that). That button is special-cased to cycle Guitarix preset banks
|
|
125
|
+
A-D instead of toggling an effect.
|
|
126
|
+
- MIDI CC numbers are the integration contract with Guitarix: `SWITCH_CC=64` (+idx per foot
|
|
127
|
+
switch), `ENCODER_CC_NUMBERS=[20,21,22,23]`, `PRESET_BANK_CC=32`, `PRESET_CHANGE_CC=0`,
|
|
128
|
+
expression pedal `MIDI_CC_NUMBER=24`. The `midi_input_thread` listens on the same virtual port
|
|
129
|
+
for CC echoes from Guitarix and updates local LED/encoder state to stay in sync when a preset
|
|
130
|
+
change alters effect state externally. Full mapping table: `docs/usage.md`.
|
|
131
|
+
- Physical pin maps for buttons/LEDs/encoders are hardcoded per-MCP as `(mcp_number, pin)` tuples
|
|
132
|
+
at the top of `daemon.py` — cross-reference against the pinout comments above
|
|
133
|
+
`encoder_configs` (which board is "1st/2nd/3rd/4th from left to right") and the tables in
|
|
134
|
+
`docs/architecture.md` before changing wiring.
|
|
135
|
+
|
|
136
|
+
### Device driver modules (`src/riffpi/`)
|
|
137
|
+
|
|
138
|
+
Each driver is a small class taking its shared hardware handles (`mcp`, `ads`, `i2c_lock`,
|
|
139
|
+
`midi_out`) in its constructor and exposing a blocking `poll()`/`poll_thread()`/`*_thread()`
|
|
140
|
+
method meant to be run in its own daemon thread; each also has an `if __name__ == "__main__"`
|
|
141
|
+
block for standalone hardware testing of just that module (only usable when run from a checkout,
|
|
142
|
+
not through the installed console script).
|
|
143
|
+
|
|
144
|
+
- `rotary_encoder.py`: quadrature decoding via a transition lookup table (`CW_transitions`/
|
|
145
|
+
`CCW_transitions` — 4-bit keys of `(last_state<<2)|current_state`), sends relative MIDI CC deltas.
|
|
146
|
+
- `keypad.py`: 4x4 matrix scan; digits accumulate into a preset number with a
|
|
147
|
+
`DIGIT_SEQUENCE_TIMEOUT` debounce window, `A`-`D` select preset banks, `*`/`#` emit virtual
|
|
148
|
+
mouse left/right clicks via `uinput`.
|
|
149
|
+
- `joystick.py`: reads the ADS1115 (`AnalogIn`), median-smooths raw voltage per axis
|
|
150
|
+
(`SMOOTHING_WINDOW`), auto-calibrates center voltage at startup (`calibrate_center()`), and
|
|
151
|
+
shapes deflection into relative `uinput` mouse motion via a dead zone (`DEAD_ZONE`) + power
|
|
152
|
+
curve (`POWER_CURVE`, must stay `>1` — a curve `<1` has infinite slope at zero and produces a
|
|
153
|
+
"dead then jumpy" feel; see the comments on the class constants).
|
|
154
|
+
- `expression_pedal.py`: reads the ADS1115, median-smooths readings, sends MIDI CC.
|
|
155
|
+
- `mcp_button.py` / `mcp_led.py`: thin per-pin wrappers around an MCP23017 pin for debounced
|
|
156
|
+
button state (`when_pressed` callback) and LED output.
|
riffpi-0.2.4/LICENSE.md
ADDED
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
CERN Open Hardware Licence Version 2 - Weakly Reciprocal
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
Preamble
|
|
5
|
+
|
|
6
|
+
CERN has developed this licence to promote collaboration among
|
|
7
|
+
hardware designers and to provide a legal tool which supports the
|
|
8
|
+
freedom to use, study, modify, share and distribute hardware designs
|
|
9
|
+
and products based on those designs. Version 2 of the CERN Open
|
|
10
|
+
Hardware Licence comes in three variants: CERN-OHL-P (permissive); and
|
|
11
|
+
two reciprocal licences: this licence, CERN-OHL-W (weakly reciprocal)
|
|
12
|
+
and CERN-OHL-S (strongly reciprocal).
|
|
13
|
+
|
|
14
|
+
The CERN-OHL-W is copyright CERN 2020. Anyone is welcome to use it, in
|
|
15
|
+
unmodified form only.
|
|
16
|
+
|
|
17
|
+
Use of this Licence does not imply any endorsement by CERN of any
|
|
18
|
+
Licensor or their designs nor does it imply any involvement by CERN in
|
|
19
|
+
their development.
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
1 Definitions
|
|
23
|
+
|
|
24
|
+
1.1 'Licence' means this CERN-OHL-W.
|
|
25
|
+
|
|
26
|
+
1.2 'Compatible Licence' means
|
|
27
|
+
|
|
28
|
+
a) any earlier version of the CERN Open Hardware licence, or
|
|
29
|
+
|
|
30
|
+
b) any version of the CERN-OHL-S or the CERN-OHL-W, or
|
|
31
|
+
|
|
32
|
+
c) any licence which permits You to treat the Source to which
|
|
33
|
+
it applies as licensed under CERN-OHL-S or CERN-OHL-W
|
|
34
|
+
provided that on Conveyance of any such Source, or any
|
|
35
|
+
associated Product You treat the Source in question as being
|
|
36
|
+
licensed under CERN-OHL-S or CERN-OHL-W as appropriate.
|
|
37
|
+
|
|
38
|
+
1.3 'Source' means information such as design materials or digital
|
|
39
|
+
code which can be applied to Make or test a Product or to
|
|
40
|
+
prepare a Product for use, Conveyance or sale, regardless of its
|
|
41
|
+
medium or how it is expressed. It may include Notices.
|
|
42
|
+
|
|
43
|
+
1.4 'Covered Source' means Source that is explicitly made available
|
|
44
|
+
under this Licence.
|
|
45
|
+
|
|
46
|
+
1.5 'Product' means any device, component, work or physical object,
|
|
47
|
+
whether in finished or intermediate form, arising from the use,
|
|
48
|
+
application or processing of Covered Source.
|
|
49
|
+
|
|
50
|
+
1.6 'Make' means to create or configure something, whether by
|
|
51
|
+
manufacture, assembly, compiling, loading or applying Covered
|
|
52
|
+
Source or another Product or otherwise.
|
|
53
|
+
|
|
54
|
+
1.7 'Available Component' means any part, sub-assembly, library or
|
|
55
|
+
code which:
|
|
56
|
+
|
|
57
|
+
a) is licensed to You as Complete Source under a Compatible
|
|
58
|
+
Licence; or
|
|
59
|
+
|
|
60
|
+
b) is available, at the time a Product or the Source containing
|
|
61
|
+
it is first Conveyed, to You and any other prospective
|
|
62
|
+
licensees
|
|
63
|
+
|
|
64
|
+
i) with sufficient rights and information (including any
|
|
65
|
+
configuration and programming files and information
|
|
66
|
+
about its characteristics and interfaces) to enable it
|
|
67
|
+
either to be Made itself, or to be sourced and used to
|
|
68
|
+
Make the Product; or
|
|
69
|
+
ii) as part of the normal distribution of a tool used to
|
|
70
|
+
design or Make the Product.
|
|
71
|
+
|
|
72
|
+
1.8 'External Material' means anything (including Source) which:
|
|
73
|
+
|
|
74
|
+
a) is only combined with Covered Source in such a way that it
|
|
75
|
+
interfaces with the Covered Source using a documented
|
|
76
|
+
interface which is described in the Covered Source; and
|
|
77
|
+
|
|
78
|
+
b) is not a derivative of or contains Covered Source, or, if it
|
|
79
|
+
is, it is solely to the extent necessary to facilitate such
|
|
80
|
+
interfacing.
|
|
81
|
+
|
|
82
|
+
1.9 'Complete Source' means the set of all Source necessary to Make
|
|
83
|
+
a Product, in the preferred form for making modifications,
|
|
84
|
+
including necessary installation and interfacing information
|
|
85
|
+
both for the Product, and for any included Available Components.
|
|
86
|
+
If the format is proprietary, it must also be made available in
|
|
87
|
+
a format (if the proprietary tool can create it) which is
|
|
88
|
+
viewable with a tool available to potential licensees and
|
|
89
|
+
licensed under a licence approved by the Free Software
|
|
90
|
+
Foundation or the Open Source Initiative. Complete Source need
|
|
91
|
+
not include the Source of any Available Component, provided that
|
|
92
|
+
You include in the Complete Source sufficient information to
|
|
93
|
+
enable a recipient to Make or source and use the Available
|
|
94
|
+
Component to Make the Product.
|
|
95
|
+
|
|
96
|
+
1.10 'Source Location' means a location where a Licensor has placed
|
|
97
|
+
Covered Source, and which that Licensor reasonably believes will
|
|
98
|
+
remain easily accessible for at least three years for anyone to
|
|
99
|
+
obtain a digital copy.
|
|
100
|
+
|
|
101
|
+
1.11 'Notice' means copyright, acknowledgement and trademark notices,
|
|
102
|
+
Source Location references, modification notices (subsection
|
|
103
|
+
3.3(b)) and all notices that refer to this Licence and to the
|
|
104
|
+
disclaimer of warranties that are included in the Covered
|
|
105
|
+
Source.
|
|
106
|
+
|
|
107
|
+
1.12 'Licensee' or 'You' means any person exercising rights under
|
|
108
|
+
this Licence.
|
|
109
|
+
|
|
110
|
+
1.13 'Licensor' means a natural or legal person who creates or
|
|
111
|
+
modifies Covered Source. A person may be a Licensee and a
|
|
112
|
+
Licensor at the same time.
|
|
113
|
+
|
|
114
|
+
1.14 'Convey' means to communicate to the public or distribute.
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
2 Applicability
|
|
118
|
+
|
|
119
|
+
2.1 This Licence governs the use, copying, modification, Conveying
|
|
120
|
+
of Covered Source and Products, and the Making of Products. By
|
|
121
|
+
exercising any right granted under this Licence, You irrevocably
|
|
122
|
+
accept these terms and conditions.
|
|
123
|
+
|
|
124
|
+
2.2 This Licence is granted by the Licensor directly to You, and
|
|
125
|
+
shall apply worldwide and without limitation in time.
|
|
126
|
+
|
|
127
|
+
2.3 You shall not attempt to restrict by contract or otherwise the
|
|
128
|
+
rights granted under this Licence to other Licensees.
|
|
129
|
+
|
|
130
|
+
2.4 This Licence is not intended to restrict fair use, fair dealing,
|
|
131
|
+
or any other similar right.
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
3 Copying, Modifying and Conveying Covered Source
|
|
135
|
+
|
|
136
|
+
3.1 You may copy and Convey verbatim copies of Covered Source, in
|
|
137
|
+
any medium, provided You retain all Notices.
|
|
138
|
+
|
|
139
|
+
3.2 You may modify Covered Source, other than Notices, provided that
|
|
140
|
+
You irrevocably undertake to make that modified Covered Source
|
|
141
|
+
available from a Source Location should You Convey a Product in
|
|
142
|
+
circumstances where the recipient does not otherwise receive a
|
|
143
|
+
copy of the modified Covered Source. In each case subsection 3.3
|
|
144
|
+
shall apply.
|
|
145
|
+
|
|
146
|
+
You may only delete Notices if they are no longer applicable to
|
|
147
|
+
the corresponding Covered Source as modified by You and You may
|
|
148
|
+
add additional Notices applicable to Your modifications.
|
|
149
|
+
|
|
150
|
+
3.3 You may Convey modified Covered Source (with the effect that You
|
|
151
|
+
shall also become a Licensor) provided that You:
|
|
152
|
+
|
|
153
|
+
a) retain Notices as required in subsection 3.2;
|
|
154
|
+
|
|
155
|
+
b) add a Notice to the modified Covered Source stating that You
|
|
156
|
+
have modified it, with the date and brief description of how
|
|
157
|
+
You have modified it;
|
|
158
|
+
|
|
159
|
+
c) add a Source Location Notice for the modified Covered Source
|
|
160
|
+
if You Convey in circumstances where the recipient does not
|
|
161
|
+
otherwise receive a copy of the modified Covered Source; and
|
|
162
|
+
|
|
163
|
+
d) license the modified Covered Source under the terms and
|
|
164
|
+
conditions of this Licence (or, as set out in subsection
|
|
165
|
+
8.3, a later version, if permitted by the licence of the
|
|
166
|
+
original Covered Source). Such modified Covered Source must
|
|
167
|
+
be licensed as a whole, but excluding Available Components
|
|
168
|
+
contained in it or External Material to which it is
|
|
169
|
+
interfaced, which remain licensed under their own applicable
|
|
170
|
+
licences.
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
4 Making and Conveying Products
|
|
174
|
+
|
|
175
|
+
4.1 You may Make Products, and/or Convey them, provided that You
|
|
176
|
+
either provide each recipient with a copy of the Complete Source
|
|
177
|
+
or ensure that each recipient is notified of the Source Location
|
|
178
|
+
of the Complete Source. That Complete Source includes Covered
|
|
179
|
+
Source and You must accordingly satisfy Your obligations set out
|
|
180
|
+
in subsection 3.3. If specified in a Notice, the Product must
|
|
181
|
+
visibly and securely display the Source Location on it or its
|
|
182
|
+
packaging or documentation in the manner specified in that
|
|
183
|
+
Notice.
|
|
184
|
+
|
|
185
|
+
4.2 Where You Convey a Product which incorporates External Material,
|
|
186
|
+
the Complete Source for that Product which You are required to
|
|
187
|
+
provide under subsection 4.1 need not include any Source for the
|
|
188
|
+
External Material.
|
|
189
|
+
|
|
190
|
+
4.3 You may license Products under terms of Your choice, provided
|
|
191
|
+
that such terms do not restrict or attempt to restrict any
|
|
192
|
+
recipients' rights under this Licence to the Covered Source.
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
5 Research and Development
|
|
196
|
+
|
|
197
|
+
You may Convey Covered Source, modified Covered Source or Products to
|
|
198
|
+
a legal entity carrying out development, testing or quality assurance
|
|
199
|
+
work on Your behalf provided that the work is performed on terms which
|
|
200
|
+
prevent the entity from both using the Source or Products for its own
|
|
201
|
+
internal purposes and Conveying the Source or Products or any
|
|
202
|
+
modifications to them to any person other than You. Any modifications
|
|
203
|
+
made by the entity shall be deemed to be made by You pursuant to
|
|
204
|
+
subsection 3.2.
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
6 DISCLAIMER AND LIABILITY
|
|
208
|
+
|
|
209
|
+
6.1 DISCLAIMER OF WARRANTY -- The Covered Source and any Products
|
|
210
|
+
are provided 'as is' and any express or implied warranties,
|
|
211
|
+
including, but not limited to, implied warranties of
|
|
212
|
+
merchantability, of satisfactory quality, non-infringement of
|
|
213
|
+
third party rights, and fitness for a particular purpose or use
|
|
214
|
+
are disclaimed in respect of any Source or Product to the
|
|
215
|
+
maximum extent permitted by law. The Licensor makes no
|
|
216
|
+
representation that any Source or Product does not or will not
|
|
217
|
+
infringe any patent, copyright, trade secret or other
|
|
218
|
+
proprietary right. The entire risk as to the use, quality, and
|
|
219
|
+
performance of any Source or Product shall be with You and not
|
|
220
|
+
the Licensor. This disclaimer of warranty is an essential part
|
|
221
|
+
of this Licence and a condition for the grant of any rights
|
|
222
|
+
granted under this Licence.
|
|
223
|
+
|
|
224
|
+
6.2 EXCLUSION AND LIMITATION OF LIABILITY -- The Licensor shall, to
|
|
225
|
+
the maximum extent permitted by law, have no liability for
|
|
226
|
+
direct, indirect, special, incidental, consequential, exemplary,
|
|
227
|
+
punitive or other damages of any character including, without
|
|
228
|
+
limitation, procurement of substitute goods or services, loss of
|
|
229
|
+
use, data or profits, or business interruption, however caused
|
|
230
|
+
and on any theory of contract, warranty, tort (including
|
|
231
|
+
negligence), product liability or otherwise, arising in any way
|
|
232
|
+
in relation to the Covered Source, modified Covered Source
|
|
233
|
+
and/or the Making or Conveyance of a Product, even if advised of
|
|
234
|
+
the possibility of such damages, and You shall hold the
|
|
235
|
+
Licensor(s) free and harmless from any liability, costs,
|
|
236
|
+
damages, fees and expenses, including claims by third parties,
|
|
237
|
+
in relation to such use.
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
7 Patents
|
|
241
|
+
|
|
242
|
+
7.1 Subject to the terms and conditions of this Licence, each
|
|
243
|
+
Licensor hereby grants to You a perpetual, worldwide,
|
|
244
|
+
non-exclusive, no-charge, royalty-free, irrevocable (except as
|
|
245
|
+
stated in subsections 7.2 and 8.4) patent licence to Make, have
|
|
246
|
+
Made, use, offer to sell, sell, import, and otherwise transfer
|
|
247
|
+
the Covered Source and Products, where such licence applies only
|
|
248
|
+
to those patent claims licensable by such Licensor that are
|
|
249
|
+
necessarily infringed by exercising rights under the Covered
|
|
250
|
+
Source as Conveyed by that Licensor.
|
|
251
|
+
|
|
252
|
+
7.2 If You institute patent litigation against any entity (including
|
|
253
|
+
a cross-claim or counterclaim in a lawsuit) alleging that the
|
|
254
|
+
Covered Source or a Product constitutes direct or contributory
|
|
255
|
+
patent infringement, or You seek any declaration that a patent
|
|
256
|
+
licensed to You under this Licence is invalid or unenforceable
|
|
257
|
+
then any rights granted to You under this Licence shall
|
|
258
|
+
terminate as of the date such process is initiated.
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
8 General
|
|
262
|
+
|
|
263
|
+
8.1 If any provisions of this Licence are or subsequently become
|
|
264
|
+
invalid or unenforceable for any reason, the remaining
|
|
265
|
+
provisions shall remain effective.
|
|
266
|
+
|
|
267
|
+
8.2 You shall not use any of the name (including acronyms and
|
|
268
|
+
abbreviations), image, or logo by which the Licensor or CERN is
|
|
269
|
+
known, except where needed to comply with section 3, or where
|
|
270
|
+
the use is otherwise allowed by law. Any such permitted use
|
|
271
|
+
shall be factual and shall not be made so as to suggest any kind
|
|
272
|
+
of endorsement or implication of involvement by the Licensor or
|
|
273
|
+
its personnel.
|
|
274
|
+
|
|
275
|
+
8.3 CERN may publish updated versions and variants of this Licence
|
|
276
|
+
which it considers to be in the spirit of this version, but may
|
|
277
|
+
differ in detail to address new problems or concerns. New
|
|
278
|
+
versions will be published with a unique version number and a
|
|
279
|
+
variant identifier specifying the variant. If the Licensor has
|
|
280
|
+
specified that a given variant applies to the Covered Source
|
|
281
|
+
without specifying a version, You may treat that Covered Source
|
|
282
|
+
as being released under any version of the CERN-OHL with that
|
|
283
|
+
variant. If no variant is specified, the Covered Source shall be
|
|
284
|
+
treated as being released under CERN-OHL-S. The Licensor may
|
|
285
|
+
also specify that the Covered Source is subject to a specific
|
|
286
|
+
version of the CERN-OHL or any later version in which case You
|
|
287
|
+
may apply this or any later version of CERN-OHL with the same
|
|
288
|
+
variant identifier published by CERN.
|
|
289
|
+
|
|
290
|
+
You may treat Covered Source licensed under CERN-OHL-W as
|
|
291
|
+
licensed under CERN-OHL-S if and only if all Available
|
|
292
|
+
Components referenced in the Covered Source comply with the
|
|
293
|
+
corresponding definition of Available Component for CERN-OHL-S.
|
|
294
|
+
|
|
295
|
+
8.4 This Licence shall terminate with immediate effect if You fail
|
|
296
|
+
to comply with any of its terms and conditions.
|
|
297
|
+
|
|
298
|
+
8.5 However, if You cease all breaches of this Licence, then Your
|
|
299
|
+
Licence from any Licensor is reinstated unless such Licensor has
|
|
300
|
+
terminated this Licence by giving You, while You remain in
|
|
301
|
+
breach, a notice specifying the breach and requiring You to cure
|
|
302
|
+
it within 30 days, and You have failed to come into compliance
|
|
303
|
+
in all material respects by the end of the 30 day period. Should
|
|
304
|
+
You repeat the breach after receipt of a cure notice and
|
|
305
|
+
subsequent reinstatement, this Licence will terminate
|
|
306
|
+
immediately and permanently. Section 6 shall continue to apply
|
|
307
|
+
after any termination.
|
|
308
|
+
|
|
309
|
+
8.6 This Licence shall not be enforceable except by a Licensor
|
|
310
|
+
acting as such, and third party beneficiary rights are
|
|
311
|
+
specifically excluded.
|
|
312
|
+
|
|
313
|
+
|