// state.ts - Peak Holder с сбросом до текущего максимума interface AppState { maxPoints: number; signalHistory: number[]; lastBufferSize: number; // Peak Holder для амплитуды peakValue: number; // Текущее удерживаемое пиковое значение амплитуды currentValue: number; // Текущий максимум из буфера peakTimer: number | null; // Таймер для сброса пика амплитуды peakHoldTime: number; // Время удержания пика в миллисекундах // Peak Holder для уровня сигнала peakSignalLevel: number; currentSignalLevel: number; // Текущий максимум уровня из буфера signalPeakTimer: number | null; signalPeakHoldTime: number; hasPeak: boolean; lastMaxSignal: number; } type PeakHolderListener = () => void; export const state: AppState = { maxPoints: 1000, signalHistory: [], lastBufferSize: 0, peakValue: 0, currentValue: 0, peakTimer: null, peakHoldTime: 3000, peakSignalLevel: 0, currentSignalLevel: 0, signalPeakTimer: null, signalPeakHoldTime: 3000, hasPeak: false, lastMaxSignal: 0, }; let peakHolderListener: PeakHolderListener | null = null; // ============================================ // ПУБЛИЧНЫЕ ФУНКЦИИ // ============================================ export function setPeakHolderListener(listener: PeakHolderListener | null): void { peakHolderListener = listener; } function notifyPeakHolderChange(): void { if (peakHolderListener) { peakHolderListener(); } } /** * Обновление пикового значения амплитуды * @param currentMax - текущий максимум из буфера (в процентах 0-100) * @returns пиковое значение */ export function updatePeakHolder(currentMax: number): number { state.currentValue = currentMax; state.lastMaxSignal = currentMax; if (currentMax >= state.peakValue) { state.peakValue = currentMax; state.hasPeak = true; scheduleAmplitudePeakRelease(); notifyPeakHolderChange(); return state.peakValue; } return state.peakValue; } /** * Обновление пикового уровня сигнала * @param currentMaxLevel - текущий максимум уровня из буфера (0-3) * @returns пиковый уровень */ export function updateSignalPeakHolder(currentMaxLevel: number): number { state.currentSignalLevel = currentMaxLevel; if (currentMaxLevel >= state.peakSignalLevel) { state.peakSignalLevel = currentMaxLevel; state.hasPeak = true; scheduleSignalPeakRelease(); notifyPeakHolderChange(); return state.peakSignalLevel; } return state.peakSignalLevel; } // ============================================ // ВНУТРЕННИЕ ФУНКЦИИ // ============================================ function scheduleAmplitudePeakRelease(): void { if (state.peakTimer !== null) { clearTimeout(state.peakTimer); state.peakTimer = null; } state.peakTimer = window.setTimeout(() => { state.peakValue = state.currentValue; state.peakTimer = null; state.hasPeak = false; notifyPeakHolderChange(); }, state.peakHoldTime); } function scheduleSignalPeakRelease(): void { if (state.signalPeakTimer !== null) { clearTimeout(state.signalPeakTimer); state.signalPeakTimer = null; } state.signalPeakTimer = window.setTimeout(() => { state.peakSignalLevel = state.currentSignalLevel; state.signalPeakTimer = null; state.hasPeak = false; notifyPeakHolderChange(); }, state.signalPeakHoldTime); } // ============================================ // ОСТАЛЬНЫЕ ФУНКЦИИ // ============================================ export function setSignalPeakHoldTime(ms: number): void { state.signalPeakHoldTime = ms; } export function getSignalPeakInfo(): { peak: number; current: number; timerActive: boolean } { return { peak: state.peakSignalLevel, current: state.currentSignalLevel, timerActive: state.signalPeakTimer !== null, }; } export function addSignal(value: number): void { state.signalHistory.push(value); if (state.signalHistory.length > state.maxPoints) { state.signalHistory = state.signalHistory.slice(-state.maxPoints); } } export function forceResetSignalPeak(): void { if (state.signalPeakTimer !== null) { clearTimeout(state.signalPeakTimer); state.signalPeakTimer = null; } state.peakSignalLevel = 0; state.currentSignalLevel = 0; state.hasPeak = false; state.lastMaxSignal = 0; notifyPeakHolderChange(); } export function forceResetPeak(): void { if (state.peakTimer !== null) { clearTimeout(state.peakTimer); state.peakTimer = null; } state.peakValue = 0; state.currentValue = 0; state.hasPeak = false; state.lastMaxSignal = 0; forceResetSignalPeak(); notifyPeakHolderChange(); } export function addSignals(values: number[], bufferSize: number): void { if (!Array.isArray(values) || values.length === 0) return; const newBytes = bufferSize - state.lastBufferSize; if (newBytes > 0 && newBytes <= values.length) { const fresh = values.slice(-newBytes); const decoded = fresh.map(b => b & 0x3F); state.signalHistory.push(...decoded); } state.lastBufferSize = bufferSize; if (state.signalHistory.length > state.maxPoints) { state.signalHistory = state.signalHistory.slice(-state.maxPoints); } } export function resetBufferTracking(): void { state.lastBufferSize = 0; forceResetPeak(); }