Files
go-service/cmd/server/web/js/state.ts
2026-06-17 15:25:46 +03:00

243 lines
7.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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;
}
type PeakHolderListener = () => void;
export const state: AppState = {
maxPoints: 1000,
signalHistory: [],
lastBufferSize: 0,
peakValue: 0,
currentValue: 0,
peakTimer: null,
peakHoldTime: 3000, // 3 секунды
peakSignalLevel: 0,
currentSignalLevel: 0,
signalPeakTimer: null,
signalPeakHoldTime: 3000,
hasPeak: false,
};
let peakHolderListener: PeakHolderListener | null = null;
// ============================================
// ПУБЛИЧНЫЕ ФУНКЦИИ
// ============================================
/**
* Установка времени удержания пика сигнала
* @param ms - время в миллисекундах
*/
// noinspection JSUnusedGlobalSymbols
export function setSignalPeakHoldTime(ms: number): void {
state.signalPeakHoldTime = ms;
}
/**
* Получение информации о пике сигнала
* @returns { peak: number; current: number; timerActive: boolean }
*/
// noinspection JSUnusedGlobalSymbols
export function getSignalPeakInfo(): { peak: number; current: number; timerActive: boolean } {
return {
peak: state.peakSignalLevel,
current: state.currentSignalLevel,
timerActive: state.signalPeakTimer !== null,
};
}
/**
* Добавление нового значения сигнала в историю
* @param value - значение сигнала
*/
// noinspection JSUnusedGlobalSymbols
export function addSignal(value: number): void {
state.signalHistory.push(value);
if (state.signalHistory.length > state.maxPoints) {
state.signalHistory = state.signalHistory.slice(-state.maxPoints);
}
}
/**
* Установка слушателя для обновления пика
* @param listener - функция-слушатель
*/
// noinspection JSUnusedGlobalSymbols
export function setPeakHolderListener(listener: PeakHolderListener | null): void {
peakHolderListener = listener;
}
/**
* Обновление пикового значения амплитуды
* @param target - текущее значение
* @returns пиковое значение
*/
// noinspection JSUnusedGlobalSymbols
export function updatePeakHolder(target: number): number {
// Обновляем текущее значение
state.currentValue = target;
// Если новое значение больше текущего пика
if (target > state.peakValue) {
// Устанавливаем новый пик
state.peakValue = target;
state.hasPeak = true;
scheduleAmplitudePeakRelease();
} else if (target < state.peakValue && state.peakTimer === null) {
// Пик выше текущего значения, но таймер пропал — перезапускаем удержание
scheduleAmplitudePeakRelease();
} // Возвращаем текущий пик
return state.peakValue;
}
/**
* Обновление пикового уровня сигнала
* @param level - текущий уровень
* @returns пиковый уровень
*/
// noinspection JSUnusedGlobalSymbols
export function updateSignalPeakHolder(level: number): number {
// Обновляем текущее значение
state.currentSignalLevel = level;
// Если новый уровень больше пика — устанавливаем новый пик
if (level > state.peakSignalLevel) {
state.peakSignalLevel = level;
state.hasPeak = true;
scheduleSignalPeakRelease();
} else if (level < state.peakSignalLevel && state.signalPeakTimer === null) {
scheduleSignalPeakRelease();
}
// Возвращаем текущий пик
return state.peakSignalLevel;
}
/**
* Принудительный сброс пика сигнала
*/
// noinspection JSUnusedGlobalSymbols
export function forceResetSignalPeak(): void {
if (state.signalPeakTimer !== null) {
clearTimeout(state.signalPeakTimer);
state.signalPeakTimer = null;
}
state.peakSignalLevel = 0;
state.currentSignalLevel = 0;
state.hasPeak = false;
}
/**
* Принудительный сброс всех пиков
*/
// noinspection JSUnusedGlobalSymbols
export function forceResetPeak(): void {
if (state.peakTimer !== null) {
clearTimeout(state.peakTimer);
state.peakTimer = null;
}
state.peakValue = 0;
state.currentValue = 0;
state.hasPeak = false;
forceResetSignalPeak();
}
/**
* Добавление массива значений сигнала
* @param values - массив значений
* @param bufferSize - размер буфера
*/
// noinspection JSUnusedGlobalSymbols
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);
}
}
/**
* Сброс отслеживания буфера
*/
// noinspection JSUnusedGlobalSymbols
export function resetBufferTracking(): void {
state.lastBufferSize = 0;
forceResetPeak();
}
// ============================================
// ВНУТРЕННИЕ ФУНКЦИИ
// ============================================
function notifyPeakHolderChange(): void {
if (peakHolderListener) {
peakHolderListener();
}
}
function scheduleAmplitudePeakRelease(): void {
// Сбрасываем старый таймер
if (state.peakTimer !== null) {
clearTimeout(state.peakTimer);
state.peakTimer = null;
}
// Запускаем новый таймер на 3 секунды
state.peakTimer = window.setTimeout(() => {
state.peakValue = state.currentValue;
state.peakTimer = null;
state.hasPeak = false;
console.log(`[Peak] Сброс пика до: ${state.peakValue}`);
notifyPeakHolderChange();
}, state.peakHoldTime);
}
function scheduleSignalPeakRelease(): void {
// Сбрасываем старый таймер
if (state.signalPeakTimer !== null) {
clearTimeout(state.signalPeakTimer);
state.signalPeakTimer = null;
}
// Запускаем новый таймер на 3 секунды
state.signalPeakTimer = window.setTimeout(() => {
// Сбрасываем пик к текущему уровню
state.peakSignalLevel = state.currentSignalLevel;
state.signalPeakTimer = null;
state.hasPeak = false;
console.log(`[SignalPeak] Сброс пика до: ${state.peakSignalLevel}`);
notifyPeakHolderChange();
}, state.signalPeakHoldTime);
}