// ---------- Слоги ---------- function syllabifyIT(w) { const isV = c => 'aeiouàèéìíòóùú'.includes(c.toLowerCase()); const onset = s => /^(str|scr|spr|spl|bl|br|cl|cr|dr|fl|fr|gl|gn|gr|pl|pr|sc|sk|sl|sm|sn|sp|sq|sr|st|sv|tr|ch|gh)/i.test(s); let out = [], syl = '', i = 0; while (i < w.length) { syl += w[i]; if (isV(w[i])) { let j = i + 1, cons = ''; while (j < w.length && !isV(w[j])) cons += w[j++]; if (j < w.length && cons.length > 0) { const k = cons.length === 1 ? 0 : onset(cons.slice(1)) ? 1 : Math.floor(cons.length / 2); syl += cons.slice(0, k); out.push(syl); syl = ''; i += k; } } i++; } if (syl) out.push(syl); return out.join('-'); } function syllabifyPhrase(text) { return text.split(/\s+/).map(syllabifyIT).join(' '); } // ---------- AudioContext для проигрывания слогов ---------- let _audioCtx = null; async function getAudioCtx() { if (!_audioCtx) _audioCtx = new (window.AudioContext || window.webkitAudioContext)(); if (_audioCtx.state === 'suspended') await _audioCtx.resume(); return _audioCtx; } let _currentBlob = null; let _currentSylBuf = null; async function playSyllable(sylIdx, total) { console.log('[SYL] click', sylIdx, '/', total, 'blob=', !!_currentBlob); if (!_currentBlob) return; try { const ctx = await getAudioCtx(); console.log('[SYL] ctx.state=', ctx.state); if (!_currentSylBuf) { const ab = await _currentBlob.arrayBuffer(); _currentSylBuf = await ctx.decodeAudioData(ab); console.log('[SYL] decoded', _currentSylBuf.duration.toFixed(1) + 's'); } const dur = _currentSylBuf.duration; const start = (dur / total) * sylIdx; const len = dur / total; const src = ctx.createBufferSource(); src.buffer = _currentSylBuf; src.connect(ctx.destination); src.start(0, start, len); console.log('[SYL] playing', start.toFixed(2) + 's-' + (start+len).toFixed(2) + 's'); } catch(e) { console.log('[SYL] ERR', e); } }