Files
go-service/cmd/server/web/js/state.ts
2026-06-22 14:38:07 +03:00

201 lines
5.9 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;
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();
}