доработка звука по уровням, разный тон
This commit is contained in:
@@ -6,9 +6,14 @@ export class AudioEngine {
|
||||
private gainNode: GainNode | null = null;
|
||||
private isPlaying: boolean = false;
|
||||
private currentLevel: number = 0;
|
||||
private currentFrequency: number = 800;
|
||||
private fadeTimeout: number | null = null;
|
||||
private readonly FREQUENCY: number = 800; // 800 Гц
|
||||
private readonly FADE_TIME: number = 0.05; // 50 мс для плавного старта/остановки
|
||||
private readonly FREQUENCY_MAP: Record<number, number> = {
|
||||
1: 800, // Уровень 1 → 800 Гц
|
||||
2: 1000, // Уровень 2 → 1000 Гц
|
||||
3: 1200 // Уровень 3 → 1200 Гц
|
||||
};
|
||||
|
||||
constructor() {
|
||||
// Инициализация при первом использовании
|
||||
@@ -34,19 +39,51 @@ export class AudioEngine {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Получение частоты для уровня
|
||||
*/
|
||||
private getFrequencyForLevel(level: number): number {
|
||||
return this.FREQUENCY_MAP[level] || 800;
|
||||
}
|
||||
|
||||
/**
|
||||
* Обновление частоты осциллятора
|
||||
*/
|
||||
private updateFrequency(frequency: number): void {
|
||||
if (!this.oscillator) return;
|
||||
|
||||
try {
|
||||
// Плавное изменение частоты за 50 мс
|
||||
const currentTime = this.audioContext?.currentTime || 0;
|
||||
this.oscillator.frequency.exponentialRampToValueAtTime(
|
||||
frequency,
|
||||
currentTime + this.FADE_TIME
|
||||
);
|
||||
this.currentFrequency = frequency;
|
||||
console.log(`[Audio] Частота: ${frequency} Гц`);
|
||||
} catch (error) {
|
||||
// Если не удалось плавно, устанавливаем сразу
|
||||
this.oscillator.frequency.value = frequency;
|
||||
this.currentFrequency = frequency;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Создание звукового графа
|
||||
*/
|
||||
private createSoundGraph(): void {
|
||||
private createSoundGraph(level: number): void {
|
||||
if (!this.audioContext) return;
|
||||
|
||||
// Останавливаем старый звук
|
||||
this.stopSound();
|
||||
|
||||
const frequency = this.getFrequencyForLevel(level);
|
||||
this.currentFrequency = frequency;
|
||||
|
||||
// Создаём осциллятор
|
||||
this.oscillator = this.audioContext.createOscillator();
|
||||
this.oscillator.type = 'sine';
|
||||
this.oscillator.frequency.value = this.FREQUENCY;
|
||||
this.oscillator.frequency.value = frequency;
|
||||
|
||||
// Создаём усилитель
|
||||
this.gainNode = this.audioContext.createGain();
|
||||
@@ -60,7 +97,7 @@ export class AudioEngine {
|
||||
this.oscillator.start();
|
||||
|
||||
this.isPlaying = true;
|
||||
console.log('[Audio] Звук создан, частота:', this.FREQUENCY, 'Гц');
|
||||
console.log(`[Audio] Звук создан, частота: ${frequency} Гц, уровень: ${level}`);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -89,11 +126,18 @@ export class AudioEngine {
|
||||
return;
|
||||
}
|
||||
|
||||
const oldLevel = this.currentLevel;
|
||||
this.currentLevel = newLevel;
|
||||
|
||||
// Получаем частоту для нового уровня
|
||||
const newFrequency = this.getFrequencyForLevel(newLevel);
|
||||
|
||||
// Если уровень > 0 и звук не создан — создаём
|
||||
if (newLevel > 0 && !this.oscillator) {
|
||||
this.createSoundGraph();
|
||||
this.createSoundGraph(newLevel);
|
||||
// Устанавливаем громкость после создания
|
||||
this.setVolume(newLevel);
|
||||
return;
|
||||
}
|
||||
|
||||
// Если уровень 0 — выключаем звук
|
||||
@@ -102,36 +146,55 @@ export class AudioEngine {
|
||||
return;
|
||||
}
|
||||
|
||||
// Если звук не играет — включаем
|
||||
// Если звук не играет — включаем заново
|
||||
if (!this.isPlaying || !this.oscillator) {
|
||||
this.createSoundGraph();
|
||||
this.createSoundGraph(newLevel);
|
||||
this.setVolume(newLevel);
|
||||
return;
|
||||
}
|
||||
|
||||
// Расчёт громкости: уровень 1 = 15%, 2 = 30%, 3 = 50%
|
||||
// Изменяем частоту, если она изменилась
|
||||
if (newFrequency !== this.currentFrequency) {
|
||||
this.updateFrequency(newFrequency);
|
||||
}
|
||||
|
||||
// Обновляем громкость
|
||||
this.setVolume(newLevel);
|
||||
|
||||
console.log(`[Audio] Уровень: ${oldLevel} → ${newLevel}, Частота: ${newFrequency} Гц`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Установка громкости для уровня
|
||||
*/
|
||||
private setVolume(level: number): void {
|
||||
if (!this.gainNode || !this.audioContext) return;
|
||||
|
||||
// Расчёт громкости: уровень 1 = 10%, 2 = 25%, 3 = 45%
|
||||
const volumeMap: Record<number, number> = {
|
||||
1: 0.10,
|
||||
2: 0.25,
|
||||
3: 0.45
|
||||
};
|
||||
|
||||
const targetVolume = volumeMap[newLevel] || 0;
|
||||
const targetVolume = volumeMap[level] || 0;
|
||||
|
||||
// Плавно меняем громкость
|
||||
if (this.gainNode) {
|
||||
try {
|
||||
const currentGain = this.gainNode.gain.value;
|
||||
// Если звук выключен или очень тихий, включаем сразу
|
||||
if (currentGain < 0.01) {
|
||||
this.gainNode.gain.setValueAtTime(targetVolume, this.audioContext!.currentTime);
|
||||
this.gainNode.gain.setValueAtTime(targetVolume, this.audioContext.currentTime);
|
||||
} else {
|
||||
// Плавное изменение за 50 мс
|
||||
this.gainNode.gain.exponentialRampToValueAtTime(
|
||||
Math.max(targetVolume, 0.001),
|
||||
this.audioContext!.currentTime + this.FADE_TIME
|
||||
this.audioContext.currentTime + this.FADE_TIME
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
// fallback
|
||||
this.gainNode.gain.value = targetVolume;
|
||||
}
|
||||
|
||||
console.log(`[Audio] Уровень: ${newLevel}, Громкость: ${(targetVolume * 100).toFixed(0)}%`);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -146,9 +209,14 @@ export class AudioEngine {
|
||||
this.fadeTimeout = null;
|
||||
}
|
||||
|
||||
// Плавно убавляем громкость за 100 мс
|
||||
const currentTime = this.audioContext.currentTime;
|
||||
this.gainNode.gain.exponentialRampToValueAtTime(0.001, currentTime + this.FADE_TIME * 2);
|
||||
try {
|
||||
// Плавно убавляем громкость за 100 мс
|
||||
const currentTime = this.audioContext.currentTime;
|
||||
this.gainNode.gain.exponentialRampToValueAtTime(0.001, currentTime + this.FADE_TIME * 2);
|
||||
} catch (error) {
|
||||
// fallback
|
||||
this.gainNode.gain.value = 0;
|
||||
}
|
||||
|
||||
// Останавливаем звук после затухания
|
||||
this.fadeTimeout = window.setTimeout(() => {
|
||||
@@ -199,6 +267,20 @@ export class AudioEngine {
|
||||
return this.isPlaying && this.currentLevel > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Получение текущей частоты
|
||||
*/
|
||||
public getCurrentFrequency(): number {
|
||||
return this.currentFrequency;
|
||||
}
|
||||
|
||||
/**
|
||||
* Получение текущего уровня
|
||||
*/
|
||||
public getCurrentLevel(): number {
|
||||
return this.currentLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Полная остановка и освобождение ресурсов
|
||||
*/
|
||||
@@ -213,6 +295,7 @@ export class AudioEngine {
|
||||
this.audioContext = null;
|
||||
}
|
||||
this.currentLevel = 0;
|
||||
this.currentFrequency = 800;
|
||||
console.log('[Audio] Ресурсы освобождены');
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user