From 7abccdf9421c2fe58976b53d279bf703dd121f1b Mon Sep 17 00:00:00 2001 From: JakubTheDeveloper Date: Thu, 10 Sep 2026 11:25:11 +0200 Subject: [PATCH] audio output description --- .vscode/extensions.json | 5 +++- README.md | 8 +++-- docs/audio-regression.md | 2 +- docs/documentation.md | 30 ++++++++++++++----- docs/manual.md | 6 +++- docs/measurements/calib-2026-09-10.json | 21 +++++++++++++ docs/measurements/calib-2026-09-10.md | 33 +++++++++++++++++++++ docs/measurements/kalib2-2026-09-10.json | 20 +++++++++++++ docs/measurements/kalib2-2026-09-10.md | 25 ++++++++++++++++ docs/measurements/sample-test-2026-09-09.md | 13 +++++--- docs/tutorial/content.js | 8 ++--- src/codec_es8388.cpp | 3 +- todo.md | 21 +------------ 13 files changed, 153 insertions(+), 42 deletions(-) create mode 100644 docs/measurements/calib-2026-09-10.json create mode 100644 docs/measurements/calib-2026-09-10.md create mode 100644 docs/measurements/kalib2-2026-09-10.json create mode 100644 docs/measurements/kalib2-2026-09-10.md diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 411655e..7062365 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -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" ] } diff --git a/README.md b/README.md index a35eea4..b7829e1 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/docs/audio-regression.md b/docs/audio-regression.md index a9d90b5..74310c3 100644 --- a/docs/audio-regression.md +++ b/docs/audio-regression.md @@ -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 diff --git a/docs/documentation.md b/docs/documentation.md index bc98626..5d0117f 100644 --- a/docs/documentation.md +++ b/docs/documentation.md @@ -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. @@ -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 diff --git a/docs/manual.md b/docs/manual.md index 20cb5ff..6b5738b 100644 --- a/docs/manual.md +++ b/docs/manual.md @@ -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 diff --git a/docs/measurements/calib-2026-09-10.json b/docs/measurements/calib-2026-09-10.json new file mode 100644 index 0000000..c714645 --- /dev/null +++ b/docs/measurements/calib-2026-09-10.json @@ -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 +} diff --git a/docs/measurements/calib-2026-09-10.md b/docs/measurements/calib-2026-09-10.md new file mode 100644 index 0000000..18a5afd --- /dev/null +++ b/docs/measurements/calib-2026-09-10.md @@ -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). diff --git a/docs/measurements/kalib2-2026-09-10.json b/docs/measurements/kalib2-2026-09-10.json new file mode 100644 index 0000000..956508b --- /dev/null +++ b/docs/measurements/kalib2-2026-09-10.json @@ -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 +} diff --git a/docs/measurements/kalib2-2026-09-10.md b/docs/measurements/kalib2-2026-09-10.md new file mode 100644 index 0000000..a611be0 --- /dev/null +++ b/docs/measurements/kalib2-2026-09-10.md @@ -0,0 +1,25 @@ +# Direct headphone calibration — 2026-09-10 + +The user supplied `~/Pulpit/kalib2.wav`, identifying it as a recording directly from the headphone socket. The input file was not modified. It is mono PCM24, 44.1 kHz, 6.250658 s. At the time of analysis, the new recording's mixer gain and precise headphone-to-mixer wiring have not been confirmed; both were requested. + +The 2–4 s steady segment was analyzed with the same normalized-PCM least-squares method as [calib.wav](calib-2026-09-10.md): optimized fundamental frequency, DC, and sine/cosine terms for harmonics 1–10. + +| Measurement | calib.wav, previous output | kalib2.wav, direct headphone socket | +| --- | ---: | ---: | +| Fundamental peak | -36.583 dBFS | -13.469 dBFS | +| Steady RMS | -39.594 dBFS | -16.479 dBFS | +| Estimated THD, harmonics 2–10 | 0.053% | 0.0044% | +| Residual RMS after fitted harmonics | -80.506 dBFS | -75.973 dBFS | + +The direct recording is **23.115 dB higher**, or approximately **14.31 times** the normalized amplitude. Its tone is stable, with no evident waveform clipping in the analyzed segment. Its fitted frequency is 1000.118 Hz. Relative THD/noise comparisons are affected by the large difference in recorded level; these measurements alone do not assign distortion to an individual component. + +**Conditional conclusion:** if the same source, Samplotron volume, mixer input/gain, routing and recording settings were used, the comparison localizes approximately 23.1 dB of attenuation to the bypassed output assembly or its connections (volume control, jack/wiring). It does not distinguish these elements individually. If input gain changed, subtract the new-minus-old gain difference from the measured 23.1 dB before estimating bypassed-path attenuation. + +Do not interpret the -13.47 dBFS recording as an absolute headphone voltage or proof that the complete analog gain is correct: the recording contains the mixer's gain and ADC scaling. Both headphone channels carry the same mono signal in phase. The final wiring uses one channel relative to headphone ground; see the repair confirmation below. + +No firmware or gain settings were changed. The original comparison was conditional on unchanged settings; the user subsequently repaired the output. Numerical results and the input SHA256 are in [kalib2-2026-09-10.json](kalib2-2026-09-10.json). + + +## 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). diff --git a/docs/measurements/sample-test-2026-09-09.md b/docs/measurements/sample-test-2026-09-09.md index b9f87a6..630eb0b 100644 --- a/docs/measurements/sample-test-2026-09-09.md +++ b/docs/measurements/sample-test-2026-09-09.md @@ -1,6 +1,6 @@ # Recording investigation: sample-test.wav, 2026-09-09 -User setup: one headphone channel through the existing 600:600 transformer, Allen & Heath ZEDi-10, JACK and Reaper at 0 dB. User reports maximum Samplotron volume and +40 channel gain. Host audio settings were not inspected or changed. +User setup: one headphone channel through the original output assembly, Allen & Heath ZEDi-10, JACK and Reaper at 0 dB. User reports maximum Samplotron volume and +40 channel gain. Host audio settings were not inspected or changed. Inputs supplied on the desktop: @@ -16,7 +16,7 @@ Levels were calculated from signed PCM normalized to its full-scale integer rang | Recorded overlap, 21–27 s | -21.682 | -36.392 | | Recorded idle, 18–21 s | -74.429 | -85.744 | -The near-full-scale source rules out a quietly prepared drum sample. The solo peak difference is about 28.3 dB between source PCM and recorded PCM; it is not a calibrated voltage measurement or a measurement of transformer loss alone. Mixer input gain, routing and converter headroom belong to the complete transfer path. The ZEDi-10 specifies 18 dB USB headroom above nominal, so a nominal analog meter indication is not 0 dBFS. Its line gain range reaches +40 dB. [Manufacturer specifications](https://www.allen-heath.com/content/uploads/2023/06/ZEDi-10-Technical-Datasheet-1.pdf). +The near-full-scale source rules out a quietly prepared drum sample. The solo peak difference is about 28.3 dB between source PCM and recorded PCM; it is not a calibrated voltage measurement or a measurement of any one component's loss. Mixer input gain, routing and converter headroom belong to the complete transfer path. The ZEDi-10 specifies 18 dB USB headroom above nominal, so a nominal analog meter indication is not 0 dBFS. Its line gain range reaches +40 dB. [Manufacturer specifications](https://www.allen-heath.com/content/uploads/2023/06/ZEDi-10-Technical-Datasheet-1.pdf). Large one-frame steps concentrate in the overlaps. Examples: 23.145850, 23.198095, 23.294966, 23.444785, 23.494127, 23.540476, 25.388503, 25.438549, 25.486508 and 26.079932 s. These were selected with absolute sample difference >0.023 FS and a 300-frame minimum separation. That threshold is a locator for this recording, not a general-purpose click detector. Many steps are spaced roughly 50 ms apart and occur during sustained overlap, rather than only at note or file boundaries. @@ -41,10 +41,15 @@ Codec startup now reads back both DAC volume registers and all four analog outpu ## Follow-up measurement -A four-second mono PCM16/44.1 kHz 1 kHz probe with -12 dBFS peak and 10 ms boundary fades was generated at `/tmp/samplotron-audio-check/calibration-1k-minus12dBFS.wav`. Its sustained sine RMS is approximately -15 dBFS. Play it at sample volume 100 to obtain a known digital reference; start the external mixer gain low, then record the settings, PFL indication and recorded level. Compare the one-channel headphone signal before and after the transformer if practical. Input socket/cable topology and actual analog levels remain to be checked. +A four-second mono PCM16/44.1 kHz 1 kHz probe with -12 dBFS peak and 10 ms boundary fades was generated at `/tmp/samplotron-audio-check/calibration-1k-minus12dBFS.wav`. Its sustained sine RMS is approximately -15 dBFS. Play it at sample volume 100 to obtain a known digital reference; start the external mixer gain low, then record the settings, PFL indication and recorded level. This probe was used for the subsequent calibration comparison. Firmware build and all 64 native test cases passed. ## Device confirmation — 2026-09-10 -The user flashed the firmware with 128-frame I2S writes and confirmed that the sound interruption disappeared. The reported overlapping-playback issue is therefore resolved in the user’s device test. This is listening feedback, not a measurement of underrun counts or maximum sustainable polyphony. Low output level remains unresolved; no level confirmation was provided. +The user flashed the firmware with 128-frame I2S writes and confirmed that the sound interruption disappeared. The reported overlapping-playback issue is therefore resolved in the user’s device test. This is listening feedback, not a measurement of underrun counts or maximum sustainable polyphony. The later audio 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). diff --git a/docs/tutorial/content.js b/docs/tutorial/content.js index fddac15..a2df1e5 100644 --- a/docs/tutorial/content.js +++ b/docs/tutorial/content.js @@ -568,19 +568,19 @@ window.SAMPLOTRON_GUIDE = { { "id": "audio-connect", "title": "03 / Connect the audio output", - "caption": "With power disconnected, connect one headphones-out channel (mono) through the 600:600 transformer to the isolated output jack and mixer. Start with a low monitoring volume.", + "caption": "With power disconnected, wire one headphones-out channel through a volume potentiometer used as a voltage divider to the mono output jack.", "left": "esp", "right": "audio", "wires": [ { "source": "HEADPHONES: L OR R", - "target": "600:600 → MONITOR", + "target": "VOL POT → MONO OUT", "color": "#74e3b4" } ], - "note": "TRS: tip (L) OR ring (R), plus sleeve (ground), to transformer primary; secondary to volume pot and isolated mono jack. Leave the other channel unconnected. Do not use L/R speaker terminals: Class-D bridge outputs add switching noise and excessive level. Speaker amplifiers, line-in and microphones are disabled.", + "note": "Pot divider: one outer lug to headphone L (tip) OR R (ring), the other to ground; wiper to output tip, output sleeve to ground. Leave the other headphone channel unconnected. Join all device-side grounds at one star point and bond it securely to an electrically continuous metal enclosure at a dedicated contact, never through a jack or pot mounting nut. Power this build from a 9 V jack → step-down to 5 V → B0505S-3WR3 isolator → AudioKit BAT; keep the supply-side return isolated from device ground. Prefer a good guitar-pedal supply over USB power; USB remains for programming. Do not use Class-D L/R speaker terminals. Speaker amplifiers, line-in and microphones remain disabled.", "command": "", - "duration": 25, + "duration": 45, "screenCues": [], "direction": { "mode": "guided", diff --git a/src/codec_es8388.cpp b/src/codec_es8388.cpp index 0e005f6..e57bfc4 100644 --- a/src/codec_es8388.cpp +++ b/src/codec_es8388.cpp @@ -101,7 +101,8 @@ bool init() { return false; } - // Playback-only ES8388 profile; output is one headphones-out channel via 600:600. + // Playback-only ES8388 profile; one headphones-out channel feeds a pot divider. + // Pot wiper -> mono jack tip; ground lug and jack sleeve -> device ground star. const uint8_t initSeq[][2] = { {kRegDacControl3, kDacControl3Muted}, // Mute, preserving default control bits. {0x01, 0x50}, // Chip Control 2: retain analog reference/bias profile. diff --git a/todo.md b/todo.md index 30cf80b..5aa2ab3 100644 --- a/todo.md +++ b/todo.md @@ -13,30 +13,11 @@ Findings from source review and targeted host-side probes of the locally installed ESP8266Audio library. Hardware noise, analog clipping, and actual SD underrun frequency still require device measurements. -- [x] **Limit the wide sum before PCM16 conversion and remove excessive fixed attenuation.** - `SamplerMixer` now uses float summation, 32 inputs and a linked look-ahead limiter. Regression tests cover unity solo level, quiet overlaps, wide peaks, phase cancellation, 32 full-scale voices, attack/release and rejected sink writes. Voice input gains no longer use 1/64 quantization or active-count gain steps. Mixer reuse aligns to the current frame or its remaining queued tail. Fade budgets/envelopes and waveform capture advance only on accepted writes. - - **Remaining hardware verification:** analog headroom (including inter-sample peaks and transformer saturation), perceived limiter pumping, SD/CPU throughput with many voices, and end/retrigger artifacts. The digital ceiling is not an oversampled true-peak guarantee. File boundary ramps, explicit fade-out and master limiting advance per accepted sample. - -- [x] **Add playback continuity regression coverage and ramp file boundaries.** - `test_audio_playback` runs the production decoder, RAM/SD source adapters, voice engine, fades and mixer. It covers single/simultaneous/staggered voices, same-sample retriggers, source-slot reuse, output backpressure, short samples and full-scale boundaries. Three tests reproduced abrupt start/EOF/retrigger steps (about 12000 PCM units for a 12000-level fixture); 35-frame smoothstep boundary ramps now pass them. A separate 6 ms fade test caught the final Q15 remainder drop; distributing that remainder removes the extra step. The retrigger policy remains a 6 ms fade of older voices. See [test details](docs/audio-regression.md). - - **Hardware feedback (2026-09-10):** the user confirmed that the reported overlapping-sample interruption disappeared after flashing the subsequent 128-frame I2S block-write firmware. The boundary tests remain separate regression coverage; broader SD/I2S timing and CPU headroom measurements remain open. - - [ ] **Make loop restarts continuous and handle voice stealing without abrupt cuts.** File edges now fade, but `restartVoiceLoop()` still closes/reopens sources and the decoder emits an initial zero on each restart. Boundary ramps prevent an instantaneous step but can cause a short amplitude dip; they do not implement a seamless crossfade or hide SD open latency. At full 32-voice occupancy, replacing the oldest voice can still cut a nonzero signal. Test seamless loops and repeated triggers at saturation before changing these policies. - [ ] **Move SD reads out of the time-critical playback path and measure underruns.** `StreamManager::BufferedSdSource` performs synchronous SD reads and has no read-ahead buffer; the local WAV decoder reads 128-byte chunks. File opening also runs in the audio task; WAV headers now come from the boot validation cache. Add a dedicated reader task and per-stream ring buffers, distinguish temporary starvation from EOF, and expose buffer occupancy and underrun counters. Stress-test multiple streams and repeated file starts on hardware; compare with RAM playback. -- [x] **Enforce the supported WAV format on preview and fallback playback paths.** - All loaded library entries are validated once during boot (PCM16, 44.1 kHz, mono and RIFF/chunk bounds), including unassigned files. Cached results gate preview, MIDI and stream fallback. Boot shows progress/rejections; library entries show `!` and a reason. Classification, RAM preload and streamed playback reuse cached PCM offsets/lengths; streams supply a canonical header from memory. Restart after SD file changes. Native tests cover malformed/unsupported files, metadata padding, read failures, cache-only classification and blocked playback paths. - - [ ] **Review ES8388 startup sequencing, register definitions, and analog gain.** - Startup now establishes I2S and digital silence before unmuting (startup hum fix confirmed on hardware), and DAC Control 3 preserves its default control bits. Remaining review: analog outputs now use `0x1E` (0 dB) with full-level digital mixing; verify available analog headroom with the actual transformer and mixer load. Choose analog levels based on measured headroom. Measure startup pops, idle noise, and distortion at several output levels, including the transformer path. Reference: [ES8388 datasheet](https://www.boardcon.com/download/ES8388_datasheet.pdf). - -- [x] **Resolve the reported interruption during overlapping playback.** - The user's `sample-test.wav` showed periodic discontinuities and increasing drum timeline lag during overlap. Switching to 128-frame I2S writes reduced per-frame driver overhead. On 2026-09-10, the user flashed the firmware and confirmed that the interruption disappeared. Transport regressions include a continuously advancing simulated clock; all 64 native tests and the ESP32 build passed. This confirms the reported case, not a measured maximum polyphony or SD throughput guarantee. Details: [recording investigation](docs/measurements/sample-test-2026-09-09.md). - -- [ ] **Investigate low output level on hardware.** - `amen.wav` peaks at -0.08 dBFS; its recorded solo peaks at -28.42 dBFS despite the reported +40 mixer gain (ZEDi-10, JACK/Reaper at 0 dB). Firmware reads back DAC/analog volume registers at boot. Analog level localization remains open; the user's confirmation about uninterrupted playback does not establish that the level issue is resolved. + Startup now establishes I2S and digital silence before unmuting (startup hum fix confirmed on hardware), and DAC Control 3 preserves its default control bits. Remaining review: analog outputs now use `0x1E` (0 dB) with full-level digital mixing; verify available analog headroom with the actual headphone/potentiometer output and mixer load. Choose analog levels based on measured headroom. Measure startup pops, idle noise, and distortion at several output levels, including the headphone output path. Reference: [ES8388 datasheet](https://www.boardcon.com/download/ES8388_datasheet.pdf).