From 448066567debb197f25f8cff5c3fab810930b64a Mon Sep 17 00:00:00 2001 From: rene Date: Sat, 6 Jun 2026 19:55:44 +0200 Subject: [PATCH] =?UTF-8?q?Navi-Sounds:=20AudioBuffer=20statt=20HTMLAudio?= =?UTF-8?q?=20=E2=80=94=20echtes=20Gebell=20zuverlaessig=20ab=20dem=20erst?= =?UTF-8?q?en=20Wuff?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit HTMLAudio+preload laedt auf iOS lazy (canplaythrough feuert nie) und verlor beim ersten Einschalten das Rennen gegen den Probe-Wuff -> Game-Boy-Fallback. Jetzt: fetch + decodeAudioData in den bestehenden AudioContext (praezises Timing via BufferSource, offline via SW-Precache); Probe-Wuff 450ms verzoegert. Synthese bleibt Fallback bei 404/Decode-Fehler. Bump v1244 --- VERSION | 2 +- backend/static/index.html | 24 ++++++------ backend/static/js/app.js | 2 +- backend/static/js/pages/routes.js | 63 +++++++++++++++++-------------- backend/static/landing.html | 2 +- backend/static/sw.js | 2 +- 6 files changed, 51 insertions(+), 44 deletions(-) diff --git a/VERSION b/VERSION index 1c49fec..c73013a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1243 \ No newline at end of file +1244 \ No newline at end of file diff --git a/backend/static/index.html b/backend/static/index.html index bc12e79..da0ca6d 100644 --- a/backend/static/index.html +++ b/backend/static/index.html @@ -86,14 +86,14 @@ Ban Yaro - + - - - - - + + + + + @@ -612,11 +612,11 @@ - - - - - + + + + + @@ -626,7 +626,7 @@ - + diff --git a/backend/static/js/app.js b/backend/static/js/app.js index 6f467eb..99ea99b 100644 --- a/backend/static/js/app.js +++ b/backend/static/js/app.js @@ -3,7 +3,7 @@ Router, State-Management, Navigation, Initialisierung. ============================================================ */ -const APP_VER = '1243'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen +const APP_VER = '1244'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen const APP_VERSION = '1.6.0'; // ← semantische Version, wird bei make release gesetzt window.APP_VER = APP_VER; // global verfügbar für andere Module (z.B. offline-indicator) window.APP_VERSION = APP_VERSION; diff --git a/backend/static/js/pages/routes.js b/backend/static/js/pages/routes.js index 8a19671..844bcdf 100644 --- a/backend/static/js/pages/routes.js +++ b/backend/static/js/pages/routes.js @@ -77,7 +77,9 @@ window.Page_routes = (() => { // ---------------------------------------------------------- const NavSound = (() => { let ctx = null; - let files = null; // { wuff, klaeffen } HTMLAudio | leer = Synthese + let bufs = null; // { wuff, klaeffen } AudioBuffer | leer = Synthese. + // HTMLAudio+preload taugt NICHT (iOS lädt lazy, canplaythrough feuert nie → + // es blieb beim Game-Boy-Sound, René 2026-06-06) → fetch + decodeAudioData. const enabled = () => { try { return localStorage.getItem('by_nav_sound') !== '0'; } catch (e) { return true; } }; function _ctx() { @@ -85,6 +87,17 @@ window.Page_routes = (() => { if (ctx.state === 'suspended') ctx.resume().catch(() => {}); return ctx; } + function _loadBufs() { + if (bufs !== null) return; + bufs = {}; + ['wuff', 'klaeffen'].forEach(name => { + fetch(`/sounds/${name}.mp3`) + .then(r => { if (!r.ok) throw new Error(String(r.status)); return r.arrayBuffer(); }) + .then(ab => _ctx().decodeAudioData(ab)) + .then(b => { bufs[name] = b; }) + .catch(() => {}); // 404/Decode-Fehler → Synthese bleibt + }); + } // Ein synthetischer „Wuff": Sägezahn-Sweep durch Tiefpass, kurzer Attack, schneller Decay. function _wuff(at, pitch = 1) { const c = _ctx(), t = c.currentTime + at; @@ -101,22 +114,23 @@ window.Page_routes = (() => { } function _barks(n, pitch, gap) { if (!enabled()) return; - const sample = files && (pitch > 1.3 ? files.klaeffen : files.wuff); - if (sample) { // echte Aufnahme (Schäferhund, /sounds/*.mp3) - // klaeffen.mp3 ist bereits eine ~2,8-s-Bell-SEQUENZ → nur 1× abspielen; - // wuff.mp3 ist ein einzelner Beller → n-mal mit Pause. - const reps = sample === files.klaeffen ? 1 : n; - let i = 0; - const play = () => { - if (i++ >= reps) return; - sample.currentTime = 0; - sample.play().catch(() => {}); - setTimeout(play, gap * 1000 + 350); - }; - play(); - return; - } - try { for (let i = 0; i < n; i++) _wuff(i * gap, pitch); } catch (e) {} + try { + const buf = bufs && (pitch > 1.3 ? bufs.klaeffen : bufs.wuff); + if (buf) { // echte Aufnahme (Schäferhund, /sounds/*.mp3) + // klaeffen.mp3 ist bereits eine ~2,8-s-Bell-SEQUENZ → nur 1× abspielen; + // wuff.mp3 ist ein einzelner Beller → n-mal mit Pause. + const c = _ctx(); + const reps = buf === bufs.klaeffen ? 1 : n; + for (let i = 0; i < reps; i++) { + const s = c.createBufferSource(); + s.buffer = buf; + s.connect(c.destination); + s.start(c.currentTime + i * (buf.duration + 0.22)); + } + return; + } + for (let i = 0; i < n; i++) _wuff(i * gap, pitch); // Fallback: Synthese + } catch (e) {} } return { enabled, @@ -126,16 +140,7 @@ window.Page_routes = (() => { const b = c.createBuffer(1, 1, 22050), s = c.createBufferSource(); s.buffer = b; s.connect(c.destination); s.start(0); } catch (e) {} - // Echte Samples einmalig anfragen (404 → Synthese bleibt) - if (files === null) { - files = {}; - ['wuff', 'klaeffen'].forEach(name => { - const a = new Audio(`/sounds/${name}.mp3`); - a.preload = 'auto'; - a.addEventListener('canplaythrough', () => { files[name] = a; }, { once: true }); - a.addEventListener('error', () => {}, { once: true }); - }); - } + _loadBufs(); // echte Samples laden (404 → Synthese bleibt) }, links() { _barks(2, 1.0, 0.30); }, // 2× Wuff rechts() { _barks(1, 1.0, 0.30); }, // 1× Wuff @@ -2198,7 +2203,9 @@ window.Page_routes = (() => { const btn = e.currentTarget; btn.style.color = on ? 'var(--c-primary)' : 'var(--c-text-secondary)'; btn.querySelector('use')?.setAttribute('href', `/icons/phosphor.svg#${on ? 'speaker-high' : 'speaker-none'}`); - if (on) { NavSound.unlock(); NavSound.rechts(); } + // Probe-Wuff leicht verzögert: gibt fetch+decodeAudioData beim ERSTEN + // Einschalten die Chance, das echte Sample zu laden (sonst Synthese-Fallback). + if (on) { NavSound.unlock(); setTimeout(() => NavSound.rechts(), 450); } UI.toast.info(on ? 'Navi-Sounds an: 2× Wuff = links, 1× Wuff = rechts, Kläffen = falscher Weg 🐕' : 'Navi-Sounds aus.'); diff --git a/backend/static/landing.html b/backend/static/landing.html index c94f1ef..0c3a932 100644 --- a/backend/static/landing.html +++ b/backend/static/landing.html @@ -4,7 +4,7 @@ - + Ban Yaro — Die Hunde-App für Deutschland, Österreich & Schweiz diff --git a/backend/static/sw.js b/backend/static/sw.js index f652d26..b22a33e 100644 --- a/backend/static/sw.js +++ b/backend/static/sw.js @@ -4,7 +4,7 @@ ============================================================ */ // ← EINZIGE Stelle für die Version — STATIC_ASSETS und CACHE_VERSION leiten sich ab -const VER = '1243'; +const VER = '1244'; const CACHE_VERSION = `by-v${VER}`; const CACHE_STATIC = `${CACHE_VERSION}-static`; const CACHE_TILES = 'ban-yaro-tiles-v1'; // bleibt über SW-Updates erhalten