You've already forked torvalds-GuitarPedal
mirror of
https://github.com/torvalds/GuitarPedal.git
synced 2026-08-14 12:44:08 +00:00
The effects have never been measured. The plumbing around them has -
boot, link gain, ring latency, the MIDI parser - but nothing has ever
asked an effect what it does to a signal, and the only DSP ever executed
off-target is the FFT in test-fft.c.
bench/ closes that. It builds audio/effect.h, effects/*.h and
single_sample() for the host and replaces the only two things the audio
core touches - the DMA read and write pointers, and the free-running
timer - with ordinary memory. So what runs is the signal path rather
than a model of it, which matters more than it sounds: a harness that
re-implemented the middle of single_sample() would be a second opinion
about what the pedal does, and a second opinion is exactly what you
cannot check an effect against.
It needed no change to anything under Software/. That is worth
recording as a fact about the architecture: apart from __not_in_flash()
in reverb.h, the effect headers have no hardware in them at all.
Measured on a transparent chain, the bench's own floor is a gain error
of -0.000265 dB and noise 144.7 dB down. The gain error is the
firmware's, not the bench's - it is eps(1.0)/2 * 512, where a 1/512 slew
stalls against float32 rounding.
bench.py drives it. The stimulus is 440 Hz because 48000/440 is 1200/11
exactly, so 12000 samples hold 110 whole cycles and every harmonic lands
on a bin with no leakage - and because 48000/440 is *not* an integer,
which is what lets aliased harmonics fall off the harmonic grid where
they can be told from honest distortion. A frequency that divides the
sample rate hides its own aliasing inside its harmonic series.
--map asks a single function out of audio/util.h directly, with no audio
path around it, so the fast approximations can be characterised against
double precision instead of being inferred through an effect that is
already distorting.
Three targets:
check-effects the two controls that say whether the instrument
works - a transparent chain has to come out
transparent, and boost's fold(), which is sharp on
purpose, has to read as sharp. Host only.
check-bench whether the bench agrees with a real pedal. Test
tone into boost's wavefolder, captured over USB, so
the path is digital end to end and a disagreement is
a real one. Every harmonic agrees to 0.00 dB and the
aliasing to 0.04 dB.
check-analog the other half: a patch cable from the output back to
the input, one board and one codec so there is no
second clock to chase. The converter pair is a gain
constant to 0.001 dB over 58 dB of level, 1.08 ms of
delay, and a residual 84.9 dB down once those two are
removed.
All three skip rather than fail when what they need is not plugged in.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
45 lines
1.3 KiB
C
45 lines
1.3 KiB
C
//
|
|
// A DMA controller made of ordinary memory.
|
|
//
|
|
// audio/effect.h reads exactly two fields - the read address of the
|
|
// transmit channel and the write address of the receive channel - and
|
|
// turns each into a pointer into i2s_dma_buf[]. That is the whole of
|
|
// the audio core's contact with the hardware, so a struct with those two
|
|
// fields in it is a complete substitute, and single_sample() runs
|
|
// unmodified against it.
|
|
//
|
|
// The bench moves these two "registers" between samples the way the DMA
|
|
// engine would: rx one slot ahead of the cpu, so the spin exits at once,
|
|
// and tx well behind it, so the deadline check stays false. See
|
|
// bench.c.
|
|
//
|
|
// uintptr_t rather than the SDK's uint32_t. The firmware stores a
|
|
// 32-bit address in a 32-bit register; here the addresses are the host's
|
|
// and a uint32_t would truncate every one of them. The '& ~7' in
|
|
// effect.h still does the right thing, because ~7 widens to all-ones
|
|
// with the low three bits clear.
|
|
//
|
|
#ifndef _BENCH_HARDWARE_DMA_H
|
|
#define _BENCH_HARDWARE_DMA_H
|
|
|
|
#include <stdint.h>
|
|
|
|
#define BENCH_DMA_CHANNELS 16
|
|
|
|
struct bench_dma_channel {
|
|
uintptr_t read_addr;
|
|
uintptr_t write_addr;
|
|
uint32_t transfer_count;
|
|
uint32_t ctrl_trig;
|
|
};
|
|
|
|
struct bench_dma {
|
|
struct bench_dma_channel ch[BENCH_DMA_CHANNELS];
|
|
};
|
|
|
|
extern struct bench_dma bench_dma_regs;
|
|
|
|
#define dma_hw (&bench_dma_regs)
|
|
|
|
#endif
|