Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"Jason2866.esp-decoder",
"pioarduino.pioarduino-ide",
"platformio.platformio-ide"
],
"unwantedRecommendations": [
"ms-vscode.cpptools-extension-pack"
"ms-vscode.cpptools-extension-pack",
"pioarduino.pioarduino-ide"
]
}
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,13 @@ Saving stores assignments, assigned sample volumes, playback modes, and the pani

Pin assignments are defined in [include/pins.h](include/pins.h); keypad note mapping is in [include/keypad_mapping.h](include/keypad_mapping.h). The [technical documentation](docs/documentation.md#2-pinout-and-buses) includes interrupt pins, keypad scanning details, and hardware notes.

The current hardware revision uses a 600:600 audio isolation transformer between **one channel of headphones out (mono)** and a jack isolated from the chassis, plus a Hi-Link `B0505S-3WR3` DC/DC isolator in the power path, to reduce ground-loop noise with an external mixer.
The audio output uses **one headphones-out channel (mono)** through a potentiometer wired as a voltage divider: one outer lug to the headphone signal, the other outer lug to ground, and the wiper to the output jack tip. Connect the jack sleeve to ground. At the headphone socket, use tip (L) or ring (R) relative to sleeve (ground), leaving the other channel unconnected. Both channels carry the same mono signal;

Take tip (left) or ring (right), plus sleeve (headphone ground), from the headphones TRS connector. Leave the other channel unconnected; do not short L and R together. The separate L/R speaker terminals are driven by bridge-tied Class-D amplifiers: they carry a switching, speaker-level signal, and neither terminal is ground. They are unsuitable for this transformer-to-mixer path. Using headphones out bypasses these amplifiers; the hardware change noticeably improved sound quality. Firmware keeps the speaker amplifiers, line-in and microphone capture paths disabled. See [audio wiring and codec configuration](docs/documentation.md#audiopower-isolation-noise-mitigation).
**Good grounding is essential:** use an electrically continuous metal enclosure, bring all device-side grounds to one star point, and bond it securely to the enclosure at a dedicated point. Do not rely on a jack or potentiometer mounting nut for the ground connection.

For normal operation, use the current build's dedicated power path: **9 V jack → step-down to 5 V → B0505S-3WR3 isolator → the AudioKit board's BAT connector**. The builder recommends good-quality guitar-pedal supplies over USB power. USB is still used for firmware programming. See [audio wiring, grounding and power](docs/documentation.md#audio-output-grounding-and-power) for the divider connections and isolated ground routing.

The separate L/R speaker terminals carry a switching, speaker-level signal from bridge-tied Class-D amplifiers; neither terminal is ground. Use headphones out for the mixer connection. Firmware keeps the speaker amplifiers, line-in and microphone capture paths disabled.

### Preparing samples and first use

Expand Down
2 changes: 1 addition & 1 deletion docs/audio-regression.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Before the boundary fix, the start and retrigger tests measured a 12000-unit jum

The existing `test_audio_mixer` suite separately checks unity gain, cancellation, linked limiting, 32 full-scale voices, aligned-sine shape against an independent unity sine, attack/release and sample acceptance. The playback suite's inferred-gain check bounds adjacent gain changes to 0.033 away from zero crossings (32-frame attack plus PCM rounding tolerance). It is a discontinuity check, not a perceptual transparency or distortion measurement.

Host tests cannot establish ESP32 CPU headroom, SD read latency, I2S underruns, transformer saturation or analog distortion. Confirm on the device with the same pair of samples played solo, simultaneously, with offsets, and retriggered, comparing RAM-loaded short samples against SD-streamed long ones. Capture the headphone-derived output if crackles remain and keep note of trigger timing and volume. Continuous loop crossfades and click-free stealing when all 32 slots are occupied remain separate work; the current suite does not certify them.
Host tests cannot establish ESP32 CPU headroom, SD read latency, I2S underruns or analog distortion. Confirm on the device with the same pair of samples played solo, simultaneously, with offsets, and retriggered, comparing RAM-loaded short samples against SD-streamed long ones. Capture the headphone-derived output if crackles remain and keep note of trigger timing and volume. Continuous loop crossfades and click-free stealing when all 32 slots are occupied remain separate work; the current suite does not certify them.


## I2S transport timing regression
Expand Down
30 changes: 22 additions & 8 deletions docs/documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,17 +53,31 @@ Source of truth: `include/pins.h`.
- Nonzero-velocity Note On messages are accepted on all channels. Velocity is not used for volume; Note Off (including zero-velocity Note On), CC, pitch bend, and MIDI clock do not control playback.
- The learned panic note takes precedence over sample playback for the same note.

### Audio/Power Isolation (Noise Mitigation)
### Audio Output, Grounding and Power

Current hardware revision includes additional isolation elements to reduce audible noise caused by ground loops between Samplotron and an external mixer:
The current hardware build takes **one channel of headphones out (mono)** through a volume potentiometer wired as a voltage divider to the mono output jack. Both headphone channels carry the same mono signal in phase. On the headphones TRS connector, tip is L, ring is R, and sleeve is headphone ground. Use either L or R relative to sleeve; leave the other channel unconnected. Do not join L and R or take the signal between them.

- audio output path: **one channel of headphones out (mono)** → `600:600` audio isolation transformer → volume potentiometer → isolated mono output jack,
- output jack: isolated from chassis,
- power path: Hi-Link `B0505S-3WR3` DC/DC isolator.
| Connection | Destination |
| --- | --- |
| One headphone channel: tip (L) or ring (R) | One outer potentiometer lug |
| Potentiometer wiper | Mono output jack tip |
| Other outer potentiometer lug | Device ground star point |
| Headphone ground / board GND | Device ground star point |
| Mono output jack sleeve | Device ground star point |

Use a TRS plug at headphones out: tip is left, ring is right, sleeve is headphone ground. Connect the transformer's primary between **either tip or ring** and sleeve. Leave the other channel unconnected; never short left and right together. The secondary feeds the volume potentiometer and mono jack, and stays electrically isolated from board ground and chassis.
The potentiometer is a voltage divider, not a two-terminal series resistor. At maximum volume its wiper reaches the signal-side lug; at minimum it reaches the ground-side lug.

Do not use the separate L/R **speaker terminals** for this path. They are outputs of bridge-tied Class-D amplifiers: both terminals are active, neither is ground, and the signal includes switching components at speaker level. A 600:600 audio transformer is not a Class-D output filter or a speaker-to-line converter; this connection can cause excessive level, buzz and distortion. Headphones out takes the signal before the speaker amplifiers. Moving the existing transformer to this connector noticeably improved sound quality on the current device.
**Grounding and enclosure continuity are essential.** Use a metal enclosure with electrical continuity across all its parts. Bring all device-side ground connections together in one star point, including board/headphone ground, the potentiometer ground lug, output jack sleeve and isolated power return. Bond that point to the enclosure through a dedicated, secure connection with good metal-to-metal contact. Do not use a jack or potentiometer mounting nut as the ground connection. Route a ground wire to the jack sleeve and the potentiometer ground lug rather than relying on mechanical mounting.

For normal operation, the builder recommends a dedicated supply jack instead of USB power. The tested power arrangement for this hardware revision is:

**9 V input jack → step-down converter set to 5 V → B0505S-3WR3 DC/DC isolator → this ESP32 AudioKit board's BAT connector.**

This allows the device to use good-quality guitar-pedal power supplies. Connect the isolated output return to the device ground star point; keep the 9 V input/converter return on the supply side of the isolator so that grounding does not bypass the isolation. Follow the actual board's connector polarity and wiring; the BAT connection above describes this build, not every ESP32 board. The programming USB port remains available for flashing and serial diagnostics.

Do not use the separate L/R **speaker terminals** for audio output. They are bridge-tied Class-D amplifier outputs: both terminals are active, neither is ground, and the signal includes switching components at speaker level. Headphones out takes the signal before those amplifiers and is the source used by the repaired output.

Hardware confirmation (2026-09-10): the user repaired the output and confirmed this wiring, grounding and power arrangement. The previously reported low output level is resolved by the hardware repair; firmware gain was not increased.

The [Ai-Thinker AudioKit V2.2 schematic (mirror)](https://github.com/johnradford49/ESP32-Audio-Kit/blob/main/esp32-audio-kit_v2.2_sch.pdf) shows the separate headphone and speaker paths. ES8388 register definitions are in the [Everest Semiconductor datasheet](https://www.armdesigner.com/download/ES8388_datasheet.pdf), sections 6.1.3–6.1.5 and 6.3.17–6.3.21.

Expand Down Expand Up @@ -219,7 +233,7 @@ The limiter stores a linked gain bound for each delayed stereo frame. An over-ce

At `VOL=100` a single voice now has unity digital gain instead of about 0.22 (the old effective gain including 1/64 quantization). Removing the old analog +4.5 dB boost gives roughly **8.7 dB higher single-voice output** below limiting, for the same WAV and external settings. This is a calculation, not an analog measurement. Quiet source files remain quiet; their dynamics are preserved. Peaks can briefly reduce other sounds in the same mix, and release means a lone voice immediately after an overload may still be attenuated.

The guarantee is a bounded **digital sample peak**, not an oversampled true-peak limit or a guarantee against transformer/mixer analog overload. [EBU peak guidance](https://qc.ebu.io/items/0084B/) distinguishes reconstructed true peaks from PCM sample peaks. Keep `CHIPPOWER=0x00`, which was confirmed quiet on this board. Verify the new level on hardware with single and overlapping samples, including bass-heavy material through the 600:600 transformer. Start the external volume low. CPU/SD throughput at high polyphony still requires an on-device check. The 32-aligned-sine regression covers the entire waveform, including the first attack and final delayed frames: maximum deviation from a unity-level reference is bounded to 128 PCM units and RMS error to 64 units. It also rejects consecutive rail samples and includes a deliberately hard-clipped negative control. These thresholds validate that specific test waveform, not arbitrary-signal transparency.
The guarantee is a bounded **digital sample peak**, not an oversampled true-peak limit or a guarantee against analog output or mixer overload. [EBU peak guidance](https://qc.ebu.io/items/0084B/) distinguishes reconstructed true peaks from PCM sample peaks. Keep `CHIPPOWER=0x00`, which was confirmed quiet on this board. Verify the new level on hardware with single and overlapping samples, including bass-heavy material through the headphone/potentiometer output. Start the external volume low. CPU/SD throughput at high polyphony still requires an on-device check. The 32-aligned-sine regression covers the entire waveform, including the first attack and final delayed frames: maximum deviation from a unity-level reference is bounded to 128 PCM units and RMS error to 64 units. It also rejects consecutive rail samples and includes a deliberately hard-clipped negative control. These thresholds validate that specific test waveform, not arbitrary-signal transparency.

## 7. UI and Device Interaction

Expand Down
6 changes: 5 additions & 1 deletion docs/manual.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@

This guide focuses on making music with Samplotron: loading sounds, mapping them to MIDI, shaping playback, and saving your setup. For SD card preparation and firmware installation, start with the [README](../README.md#preparing-samples-and-first-use).

Connect the isolated mono output jack to your mixer and start at a low monitoring volume. Inside Samplotron, this jack is fed from **one channel of headphones out through a 600:600 transformer**. Do not use the AudioKit's separate L/R speaker terminals: their Class-D amplifiers produce a switching, speaker-level signal unsuitable for this connection. Line-in and microphones are disabled; load samples from the SD card.
Connect the mono output jack to your mixer and start at a low monitoring volume. Inside Samplotron, **one headphones-out channel feeds a potentiometer used as a voltage divider**: one outer lug receives the headphone signal, the other connects to ground, and the wiper feeds the output jack tip. The jack sleeve connects to ground. Do not use the AudioKit's separate L/R speaker terminals: their Class-D amplifiers produce a switching, speaker-level signal unsuitable for this connection. Line-in and microphones are disabled; load samples from the SD card.

For a quiet output, all device-side grounds meet at one star point, bonded to a metal enclosure with full electrical continuity through a dedicated, secure contact. A jack or potentiometer mounting nut must not serve as that ground connection.

The current build uses **9 V input → step-down to 5 V → B0505S-3WR3 isolator → the AudioKit board's BAT connector**, allowing good-quality guitar-pedal supplies. Prefer this dedicated power input over USB for normal operation; use the programming USB port for firmware updates. See the [build wiring](documentation.md#audio-output-grounding-and-power) for grounding and connector details.

## 1. Power On and Wait for Ready

Expand Down
21 changes: 21 additions & 0 deletions docs/measurements/calib-2026-09-10.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"fundamental_hz": 1000.1183438584645,
"fundamental_peak_dbfs": -36.58346364344135,
"steady_rms_dbfs": -39.59374142868431,
"harmonics_2_to_10_thd_percent": 0.05304409215340069,
"residual_rms_dbfs": -80.50640124104365,
"dc": 1.4651689900654404e-05,
"source_to_recording_db": -24.58346364344135,
"file": "calib.wav",
"sha256": "70ed34a3210a70e33dbd2975cd6d7e64aade63a51f061428b1c5fae6d5297290",
"sample_rate_hz": 44100,
"pcm_bits": 24,
"channels": 1,
"duration_seconds": 7.1893424036281175,
"analysis_window_seconds": [
3,
5
],
"reference_peak_dbfs": -12,
"reported_mixer_gain_db": 40
}
33 changes: 33 additions & 0 deletions docs/measurements/calib-2026-09-10.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Calibration recording — 2026-09-10

The user recorded the previously generated 1 kHz, -12 dBFS peak probe as `~/Pulpit/calib.wav`, using the same Samplotron settings, ZEDi-10 channel gain +40 dB, and JACK/Reaper at 0 dB. The temporary reference WAV is no longer present in `/tmp`; its known generation parameters are recorded in the [earlier investigation](sample-test-2026-09-09.md). No host audio settings were accessed or changed.

`calib.wav` is mono PCM24 at 44.1 kHz, lasting 7.189342 s. It contains silence followed by approximately four seconds of tone. Analysis uses the steady 3–5 s portion, excluding onset and EOF. Signed PCM was divided by 8388608; no gain or normalization was applied.

| Measurement | Result |
| --- | ---: |
| Known source sine peak | -12 dBFS |
| Fitted recorded sine peak | -36.583 dBFS |
| Recorded steady RMS | -39.594 dBFS |
| Source-to-recording digital level difference | -24.583 dB |
| Fitted fundamental frequency | 1000.118 Hz |
| Estimated THD, harmonics 2–10 | 0.053% |
| Residual RMS after fitting DC and harmonics 1–10 | -80.506 dBFS |
| Idle RMS, representative 0.25 s windows | about -85.3 dBFS |

The peak was obtained by least-squares sine/cosine fitting, with frequency optimized between 999.95 and 1000.3 Hz. THD is the root-sum-square amplitude of fitted harmonics 2–10 divided by fundamental amplitude. The residual includes noise, clock variation, unmodeled distortion and fitting error; it is not an independently calibrated noise measurement. The approximately 118 ppm frequency difference can reflect the combined playback/recording clocks.

The stable recorded tone has no waveform clipping evident in this analysis. Its level is approximately 17 times smaller in normalized PCM amplitude than the source. This establishes substantial attenuation in the complete source-to-recording transfer, even with the reported input gain, but does not locate it in the codec, output assembly, cable or mixer routing.

Do not add the reported +40 dB directly to the PCM level difference and label the result a measured analog loss: source DAC voltage calibration, mixer input path and ADC full-scale mapping have not been measured. The ZEDi-10 specifies 18 dB USB headroom above nominal and provides multiple recording-source routes. [Manufacturer specifications](https://www.allen-heath.com/content/uploads/2023/06/ZEDi-10-Technical-Datasheet-1.pdf).

Firmware already uses unity gain for a solo voice at VOL=100 outside the brief boundary ramps, with DAC and analog volume set to 0 dB and checked by register readback at boot. Existing regression tests cover the digital unity path. Increasing digital gain without identifying the loss would push near-full-scale source material into the limiter. No firmware gain change was made in response to this recording.

The direct-headphone comparison was subsequently supplied as `kalib2.wav`; see [its analysis](kalib2-2026-09-10.md).

The source recording was not modified. Numerical results and the recording SHA256 are stored in [calib-2026-09-10.json](calib-2026-09-10.json). Uninterrupted playback was already confirmed by the user separately. The later output repair is recorded below.


## Hardware repair confirmed — 2026-09-10

The user repaired the audio output. The final build uses one headphone channel through a potentiometer voltage divider, with a common device ground star and a dedicated bond to a continuous metal enclosure. Normal power is 9 V input, step-down to 5 V, B0505S-3WR3 isolation and this AudioKit board's BAT connector. The low-level investigation is closed based on the user's repair confirmation; the measurements above describe the earlier setup. No firmware gain increase was needed. See [current wiring](../documentation.md#audio-output-grounding-and-power).
20 changes: 20 additions & 0 deletions docs/measurements/kalib2-2026-09-10.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"file": "kalib2.wav",
"sha256": "4db9c890edef2fb4476776294d2273e47a1bf1153dab3a871fd91bc0ce81d0fd",
"sample_rate_hz": 44100,
"pcm_bits": 24,
"channels": 1,
"duration_seconds": 6.250657596371882,
"analysis_window_seconds": [
2,
4
],
"fundamental_hz": 1000.1180520276966,
"fundamental_peak_dbfs": -13.468860188413856,
"steady_rms_dbfs": -16.479054971362075,
"harmonics_2_to_10_thd_percent": 0.00441074446408979,
"residual_rms_dbfs": -75.97294664366251,
"mixer_gain_db": null,
"connection": "direct headphone output; exact wiring not yet confirmed",
"recorded_level_difference_vs_calib_db": 23.114603455027492
}
Loading
Loading