You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(audio): smart forward/backward seek with press-coalescing
Replace the ad-hoc 5-minute seek that commit 76e1535 bolted onto the
next/previous-track buttons (it overshot on VBR/FLAC, silently jumped to
the next track near a file boundary, and re-synced the decoder on every
single press so it felt sluggish and dropped presses).
- Revert NEXTTRACK/PREVIOUSTRACK to upstream behavior (incl. the
"previous track only when <5s in, else restart" logic).
- Add CMD_SMART_FORWARDS/BACKWARDS (action codes 190/191) plus
track-control codes SMARTFORWARD/SMARTBACKWARD (10/11). On a single
long file they seek inside the file; on a multi-file playlist they fall
back to next/previous track.
- Coalesce rapid presses: the offset accumulates and is applied once
presses settle (smartSeekCoalesceMs), so the decoder re-syncs once
instead of once per press.
- Step configurable in the web UI (General -> options -> "Smart seek
step (sec.)", NVS key seekStep, default 300), applied live without a
reboot. de/en/fr locales, Swagger general schema, and the GitHub-Pages
demo mock updated.
- MQTT: smart seek works via the existing track-control topic (codes
10/11); web/REST via the controls "action" command.
Built for the complete env and flashed/verified on device (the new
seekStep setting round-trips through /settings).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: README.md
+2-1Lines changed: 2 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -237,13 +237,14 @@ neon logo that doubles as the SVG favicon ([`7be5254`](../../commit/7be5254)):
237
237
| Ready sound on cold start |[`c051c40`](../../commit/c051c40)|
238
238
| Cyberpunk "Data Drop" idle LED animation |[`f20b111`](../../commit/f20b111)|
239
239
| Selectable idle animation (standard idle dots or cyberpunk "Data Drop") in the LED settings; defaults to standard |[`f6c3f4e`](../../commit/f6c3f4e)|
240
-
| Improved button responsiveness and track navigation seek options|[`76e1535`](../../commit/76e1535)|
240
+
| Improved button responsiveness (faster debounce). The original 5-minute seek hack on the next/previous-track buttons has since been reverted to upstream behavior and replaced by dedicated smart-seek commands (see below)|[`76e1535`](../../commit/76e1535)|
241
241
| Unlocking controls via button press while locked |[`d83e15f`](../../commit/d83e15f)|
242
242
| Support for a 6th button |[`b116151`](../../commit/b116151)|
243
243
| OLED display support (SH1106/SSD1306 128×64 over I2C): boot splash, idle screen with IP + READY, now-playing title (up to 3 lines, scrolling) with battery/time/wifi status bar, and a volume bar |[`8ce8104`](../../commit/8ce8104)|
244
244
| Web-configurable OLED (new **OLED** settings tab): enable/disable the display, pick the startup animation (none / boot terminal / login splash / full), set the idle header text, toggle the battery/time/wifi/volume fields, and flip the panel 180°. Also a `CMD_TOGGLE_OLED` command for keybindings to blank the screen (e.g. at night) |[`7d86c3d`](../../commit/7d86c3d)|
245
245
| Audiobook resume fade-in: continuing a saved position briefly stutters in the first ~2 s (file open + MP3 header decode + seek-flush saturate the 1-bit SD/CPU while I2S already plays). The resume now rewinds a few seconds and fades the volume up over that span, so the glitch lands on already-heard audio — no content lost, clean sound from where you stopped. Tunable / disable via `RESUME_FADEIN_DURATION_MS` and `RESUME_FADEIN_REWIND_S` in `settings.h`|[`583225f`](../../commit/583225f)|
246
246
| Audiobooks restart from the beginning after a long pause: if a position-saving audiobook card has not been played for a configurable span (new **"Restart audiobook after (hrs)"** general setting, default 24 h, 0 = off), the next tap starts the book over instead of resuming mid-chapter — handy for kids who no longer remember where they were. The per-card last-seen timestamp lives in its own NVS namespace and is only consulted when the clock is valid (NTP/RTC) |[`445e290`](../../commit/445e290)|
247
+
|**Smart forward/backward seek with press-coalescing** (`CMD_SMART_FORWARDS` / `CMD_SMART_BACKWARDS`, action codes 190/191; also track-control codes 10/11 for MQTT): on an audiobook that is a single long file these commands seek *inside* the file; on a playlist of several files they fall back to next/previous track. Rapid presses are bundled into one jump so the decoder re-syncs once instead of once per press (the old per-press seek felt sluggish on FLAC and dropped presses during the multi-second resync). The step is configurable in the web UI (General → options → **"Smart seek step (sec.)"**, NVS key `seekStep`, default 300 s = 5 min). Bind them to physical buttons in the **Buttons** settings tab. The plain `CMD_SEEK_FORWARDS`/`BACKWARDS` 30 s jump (`jumpOffset`) and the upstream next/previous-track behavior are both unchanged |[`PENDING`](../../commit/PENDING)|
Copy file name to clipboardExpand all lines: html/locales/de.json
+2Lines changed: 2 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -694,6 +694,8 @@
694
694
"savePlayPosPeriodicExp": "Während ein Hörbuch läuft, wird die Position alle ~30 s im Flash gesichert. So gehen bei einem unerwarteten Stromausfall (leerer Akku, harter Aus-Schalter) nur die letzten Sekunden verloren statt bis zum Anfang des Tracks zurückzuspringen. Fork-Funktion.",
695
695
"restartFreshHrs": "Hörbuch von vorn nach (Std.)",
696
696
"restartFreshHrsExp": "Wird ein Hörbuch länger als die angegebene Stundenzahl nicht abgespielt, startet es beim nächsten Auflegen wieder von vorn statt an der gespeicherten Stelle. Praktisch für Kinder, die sich nach einem Tag Pause nicht mehr erinnern, wo sie waren. 0 = aus (immer fortsetzen). Standard: 24. Benötigt eine gültige Uhrzeit (NTP/RTC). Fork-Funktion.",
697
+
"seekStep": "Smart-Spulen Schritt (Sek.)",
698
+
"seekStepExp": "Sprungweite in Sekunden für die Befehle „Smart vor/zurück\" (CMD_SMART_FORWARDS/BACKWARDS). Bei einem Hörbuch, das aus einer einzigen langen Datei besteht, spulen diese Tasten innerhalb der Datei; bei einer Playlist aus mehreren Dateien wechseln sie stattdessen den Track. Mehrere schnelle Tastendrücke werden zu einem Sprung gebündelt (nur ein Neu-Puffern statt vieler). Standard: 300 (5 Min.). Fork-Funktion.",
697
699
"pauseIfRfidRemoved": "Pause wenn RFID-Tag entfernt",
698
700
"pauseIfRfidRemovedExp": "Pausieren wenn RFID-Tag entfernt wird. Mehr Infos <a href='https://forum.espuino.de/t/welche-optionen-beim-kompilieren-gibt-es/120' target='_blank'>hier</a> unter <code>PAUSE_WHEN_RFID_REMOVED</code>.",
Copy file name to clipboardExpand all lines: html/locales/en.json
+2Lines changed: 2 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -694,6 +694,8 @@
694
694
"savePlayPosPeriodicExp": "While an audio book plays, the position is saved to flash every ~30 s. This way an unexpected power loss (dead battery, hard power-off) only loses the last few seconds instead of falling back to the start of the track. Fork feature.",
695
695
"restartFreshHrs": "Restart audiobook after (hrs)",
696
696
"restartFreshHrsExp": "If an audiobook has not been played for more than the given number of hours, it starts over from the beginning the next time the card is placed, instead of resuming the saved position. Handy for kids who, after a day's break, no longer remember where they were. 0 = off (always resume). Default: 24. Requires a valid clock (NTP/RTC). Fork feature.",
697
+
"seekStep": "Smart seek step (sec.)",
698
+
"seekStepExp": "Jump distance in seconds for the \"smart forward/backward\" commands (CMD_SMART_FORWARDS/BACKWARDS). On an audiobook that is a single long file these buttons seek within the file; on a playlist of several files they change tracks instead. Several quick presses are coalesced into one jump (a single re-buffer instead of many). Default: 300 (5 min). Fork feature.",
697
699
"pauseIfRfidRemoved": "Pause when RFID tag is removed",
698
700
"pauseIfRfidRemovedExp": "Playback is paused when the RFID tag is removed. More information <a href='https://forum.espuino.de/t/welche-optionen-beim-kompilieren-gibt-es/120' target='_blank'>here</a> under <code>PAUSE_IF_RFID_REMOVED</code>.",
699
701
"stopIfRfidRemoved": "Stop instead of pause on removal",
Copy file name to clipboardExpand all lines: html/locales/fr.json
+2Lines changed: 2 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -683,6 +683,8 @@
683
683
"savePlayPosPeriodicExp": "Pendant la lecture d'un livre audio, la position est enregistrée dans la mémoire flash toutes les ~30 s. Ainsi, une coupure de courant inattendue (batterie vide, arrêt brutal) ne perd que les dernières secondes au lieu de revenir au début de la piste. Fonction du fork.",
684
684
"restartFreshHrs": "Redémarrer le livre audio après (h)",
685
685
"restartFreshHrsExp": "Si un livre audio n'a pas été lu depuis plus que le nombre d'heures indiqué, il recommence depuis le début lors de la prochaine pose de la carte, au lieu de reprendre à la position enregistrée. Pratique pour les enfants qui, après une journée de pause, ne se souviennent plus où ils en étaient. 0 = désactivé (toujours reprendre). Par défaut : 24. Nécessite une horloge valide (NTP/RTC). Fonction du fork.",
686
+
"seekStep": "Pas d'avance rapide intelligente (s)",
687
+
"seekStepExp": "Distance de saut en secondes pour les commandes « avance/recul intelligent » (CMD_SMART_FORWARDS/BACKWARDS). Pour un livre audio constitué d'un seul fichier long, ces touches avancent à l'intérieur du fichier ; pour une liste de plusieurs fichiers, elles changent de piste. Plusieurs appuis rapides sont regroupés en un seul saut (une seule remise en mémoire tampon au lieu de plusieurs). Par défaut : 300 (5 min). Fonction du fork.",
686
688
"pauseIfRfidRemoved": "Mettre en pause si la balise RFID est retirée",
687
689
"pauseIfRfidRemovedExp": "Mettre en pause la lecture si la balise RFID est retirée. Plus d'informations <a href='https://forum.espuino.de/t/welche-optionen-beim-kompilieren-gibt-es/120' target='_blank'>ici</a> sous <code>PAUSE_IF_RFID_REMOVED</code>.",
688
690
"stopIfRfidRemoved": "Arrêter au lieu de mettre en pause",
Copy file name to clipboardExpand all lines: src/AudioPlayer.h
+4Lines changed: 4 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -51,6 +51,8 @@ typedef struct { // Bit field
51
51
boolstopIfRfidRemoved : 1; // When pauseIfRfidRemoved is active: stop playback instead of pausing when RFID is removed.
52
52
booldontAcceptRfidTwice : 1; // RFID-reader doesn't accept the same RFID-tag twice in a row (unless it's a modification-card or RFID-tag is unknown in NVS). Flag will be ignored silently if PAUSE_WHEN_RFID_REMOVED is active. (https://forum.espuino.de/t/neues-feature-dont-accept-same-rfid-twice/1247)
53
53
int16_tjumpToFolderTrack=-1; // track to jump to
54
+
int32_tsmartSeekPendingSec=0; // accumulated smart-seek offset (seconds, signed) waiting to be applied; coalesces rapid presses
55
+
uint32_tsmartSeekRequestMs=0; // millis() of the last smart-seek press; the offset is applied once presses settle
0 commit comments