0
mirror of https://github.com/torvalds/GuitarPedal.git synced 2026-08-14 04:43:53 +00:00
Files
Linus Torvalds 5c1d15e687 Validation: say which pedal, when there is more than one
test-bench, test-analog and measure-load all took whatever enumerated
first, and test-audio took its card from one enumeration and its MIDI
port from another - so with two boards attached it could have measured
the audio of one and talked to the other.  test-bench and test-analog at
least refused to guess and skipped; the other two did not.

All four go through pedal.discover() now and take --target (-t for
measure-load), which is passed to pedal.find() - already written to
refuse ambiguity rather than answer with the first hit.  Refusing is
still the default: no target and more than one board is a skip, not a
guess.  The Makefile passes TARGET= through, the same way check-boot
already did.

This is not hypothetical tidying.  Two boards of one revision differ
only in their serial, and the run that matters is the one where a
suspected board is compared against a known-good one - which is exactly
when picking the wrong one is both easy and invisible.

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2026-08-11 20:53:23 -07:00

244 lines
8.9 KiB
Makefile

CC = gcc
CFLAGS = -Wall -O2 -I.. -I../Firmware -I../build/ \
-ffast-math -fsingle-precision-constant -Wfloat-conversion
visualize: test-fft
python visualize.py DADGAD.wav
test-fft: test-fft.c
test-midi-cin: test-midi-cin.c
#
# The effect bench: the pedal's own audio core, built for the host.
#
# Everything it needs is generated here rather than taken from
# ../build, so it does not need the firmware to have been built
# and never writes into the source tree. The three math tables carry
# the shift values from CMakeLists.txt; if those move, these
# have to move with them, and the bench will be measuring a different
# pedal until they do.
#
# The include paths want a word. Three of the four are the top-level
# directories the bench compiles against - the repository root so that
# "Audio/x.h" and the generated map's "Effects/y.h" resolve from
# wherever they are included, ../Firmware for the pedal-side headers the
# audio core reaches for (status.h, effect-state.h), and ../Audio
# because the files in there include each other by bare name. The
# fourth, bench/shim, has to come first: it is how a workstation gets
# past the things that only exist on an M33.
#
BENCH_GEN = bench/gen
BENCH_HDRS = $(BENCH_GEN)/effect_map.h $(BENCH_GEN)/pow2.h \
$(BENCH_GEN)/log2.h $(BENCH_GEN)/quarter_sine.h
BENCH_CFLAGS = -Wall -Wno-unused-function -O2 \
-ffast-math -fsingle-precision-constant -Wfloat-conversion \
-DSAMPLES_PER_SEC=48000.0f \
-Ibench/shim -I$(BENCH_GEN) -I.. -I../Firmware -I../Audio
$(BENCH_GEN)/effect_map.h: $(wildcard ../Effects/*.h) \
../scripts/gen_effects.py
@mkdir -p $(BENCH_GEN)
python3 ../scripts/gen_effects.py ../Effects/ \
$(BENCH_GEN)/effect_map.h $(BENCH_GEN)/effects.js \
$(BENCH_GEN)/dummy_map.md
$(BENCH_GEN)/pow2.h: ../scripts/pow2.py
@mkdir -p $(BENCH_GEN)
python3 $< $@ 8
$(BENCH_GEN)/log2.h: ../scripts/log2.py
@mkdir -p $(BENCH_GEN)
python3 $< $@ 8
$(BENCH_GEN)/quarter_sine.h: ../scripts/quarter_sine.py
@mkdir -p $(BENCH_GEN)
python3 $< $@ 8
bench/bench: bench/bench.c $(BENCH_HDRS) \
$(wildcard bench/shim/*/*.h bench/shim/*/*/*.h) \
$(wildcard ../Audio/*.h) ../Firmware/effect-state.h \
../Firmware/status.h
$(CC) $(BENCH_CFLAGS) -o $@ $< -lm
#
# The same headers, without the audio path: just the biquad
# constructors, so a filter can be asked where it landed.
#
#
# All three math tables, not just the sine: Audio/util.h includes pow2.h
# and log2.h too, and coeff.c reaches util.h through biquad.h. Only the
# sine was listed, which worked for as long as nobody built this target
# with an empty gen/ - 'make bench' builds bench/bench first and that
# generates all three, so the gap stayed hidden.
#
bench/coeff: bench/coeff.c $(BENCH_GEN)/quarter_sine.h \
$(BENCH_GEN)/pow2.h $(BENCH_GEN)/log2.h \
$(wildcard bench/shim/*/*.h) $(wildcard ../Audio/*.h)
$(CC) $(BENCH_CFLAGS) -o $@ $< -lm
bench: bench/bench bench/coeff
#
# What the bench is for is looking at one effect, which is a
# conversation and not a target. What belongs in 'check' is only the
# part that has a right answer: the two controls that say whether the
# instrument is working at all. A bench that passes these and an effect
# that then reads strangely is a finding; a bench that fails these makes
# every other number in the session worthless.
#
check-effects: bench/bench
./test-effects.py
#
# Where every biquad in the pedal actually lands, swept across the range
# the pots offer. Host arithmetic only, so it needs no hardware and is
# part of 'check'.
#
check-biquad: bench/coeff
./test-biquad.py
#
# Do the pages in Documentation/effects still describe the effects, and
# do their charts still draw?
#
# Not slow - three seconds for a page, because bench.py parallelises the
# sweeps and mmdc takes the whole markdown file in one browser start.
# It is out of 'check' for the other reason: drawing the charts wants
# node and a headless browser, fetched through npx the first time, and
# 'check' should stay runnable with nothing but python and a compiler.
# It says so rather than skipping quietly when it cannot draw them.
#
# This is the target to run after changing an effect, which is exactly
# when a page goes stale - the last analysis was wrong from the moment
# single_pole_freq() was fixed under it, and nothing said so for a day.
#
check-analysis: bench/bench
./check-analysis.py
#
# The other half of the bench: whether it agrees with a real pedal.
#
# Separate from check-effects because it needs hardware, and separate
# from check-hw because it needs no signal generator - the stimulus is
# [TESTTONE] and the capture is the pedal's own USB audio, so the path
# is digital end to end. Skips when there is no pedal plugged in.
#
check-bench: bench/bench
./test-bench.py $(if $(TARGET),--target $(TARGET))
#
# The analog half, which needs a patch cable from the pedal's output
# back to its own input and nothing else. One board, one cable, so the
# DAC and the ADC are the same codec on the same clock and there is no
# drift to chase.
#
# Reports and never fails. What it measures is a converter and a cable
# rather than any code of ours, and 95 is the issue about a bench
# measurement that carries no record of the bench - so this prints
# numbers and lets a person decide whether the cable moved.
#
check-analog:
./test-analog.py $(if $(TARGET),--target $(TARGET))
#
# The web app gets checked too, which needs node.
#
# Skipped rather than fatal when node isn't installed: it is the only
# thing here that needs anything beyond a C compiler and python, and
# 'make check' should still be worth running without it. It says so when
# it skips, so it can't quietly stop testing anything.
#
NODE := $(shell command -v node 2>/dev/null)
#
# The hardware half. Wants a pedal on the USB and a signal generator on
# its input, so it is a separate target rather than part of 'check' -
# and it skips rather than fails when there is nothing plugged in, the
# same bargain the node check makes below.
#
# The generator cannot be set from here. --ptp and --freq say what it
# is set to, and every number that depends on it is reported against
# what was declared.
#
check-hw:
./test-audio.py --ptp 0.100 --freq 440 $(if $(TARGET),--target $(TARGET))
#
# Separate from check-hw because it reflashes: planting a scene with
# channel routing in it means a trip through BOOTSEL, since nothing sets
# that over MIDI yet. It leaves two scenes behind in the save area.
#
check-split:
./test-split.py
#
# Two pedals, patched output to input in both directions, one generating
# and the other measured. Separate from check-hw because it needs the
# second board, and because what it is for is different: check-hw asks
# whether the pedal does the right thing to a signal somebody else
# provides, and this asks the questions that need the signal to be under
# the test's control - what the analog link does, how quiet a properly
# driven input is, and whether the audio survives the pedal's own sysex.
#
check-loop:
./test-loop.py
#
# The hardware MIDI jacks, through a USB-MIDI adapter on the other end.
#
# Reports and never fails. The adapter is a cheap CH345 and the path has
# shown intermittent trouble nobody has pinned down, so wiring it into a
# gate would only teach us to ignore the gate. What is wanted is the
# rate: run it, watch the number, and let the data say whether the
# flakiness is the dongle, the parser, or nothing.
#
check-midi:
./test-midi.py
#
# Cold power cycles on one board, tallied. Needs a hand on the USB plug
# - there is no switched hub here - so it is as far from 'check' as a
# target gets, and it takes a --target because cycling the wrong board
# yields a number indistinguishable from a real one.
#
# make check-boot TARGET=7989 JSON=boot-A.json
#
TARGET ?=
JSON ?=
check-boot:
./test-boot.py $(if $(TARGET),--target $(TARGET)) \
$(if $(JSON),--json $(JSON)) $(BOOTARGS)
#
# The same hang, chased unattended through BOOTSEL instead of through the
# plug. Cheap enough to leave running, and blind to whatever needs a
# genuinely cold crystal - a clean run here is not a fixed pedal. See
# the header of test-reboot.py before believing a result either way.
#
check-reboot:
./test-reboot.py $(if $(TARGET),--target $(TARGET)) \
$(if $(JSON),--json $(JSON)) $(BOOTARGS)
check: test-midi-cin bench/coeff
./test-midi-cin
./test-biquad.py
ifeq ($(NODE),)
@echo "test-webmidi: SKIPPED - no node in PATH"
else
@#
@# effects.js is generated, so generate it - into a temp directory,
@# because a test has no business writing into the source tree, and
@# this way it doesn't matter whether the firmware has been built.
@#
@t=`mktemp -d` && \
python3 ../scripts/gen_effects.py ../Effects/ \
$$t/dummy_map.h $$t/effects.js $$t/dummy_map.md && \
$(NODE) test-webmidi.js $$t/effects.js; \
r=$$?; rm -rf $$t; exit $$r
endif
.PHONY: bench check check-analog check-analysis check-bench check-biquad
.PHONY: check-boot check-effects check-hw check-loop
.PHONY: check-midi check-reboot check-split