ubbhjbj
This commit is contained in:
8192
frontend/src/pages/test/ews-component-master/spectrum.txt
Normal file
8192
frontend/src/pages/test/ews-component-master/spectrum.txt
Normal file
File diff suppressed because it is too large
Load Diff
@@ -15,24 +15,68 @@ export function RetroSoundTest() {
|
|||||||
return audioCtxRef.current;
|
return audioCtxRef.current;
|
||||||
};
|
};
|
||||||
|
|
||||||
const playSound = (freq: number, type: OscillatorType, duration: number, vol: number, fade: boolean = false) => {
|
// Helper: Create audio chain (oscillator → filter → gain → output)
|
||||||
const ctx = getAudioCtx();
|
const createFilteredOscillator = (
|
||||||
|
ctx: AudioContext,
|
||||||
|
startTime: number,
|
||||||
|
hz: number,
|
||||||
|
volume: number,
|
||||||
|
oscType: OscillatorType,
|
||||||
|
filterFreq: number
|
||||||
|
) => {
|
||||||
const osc = ctx.createOscillator();
|
const osc = ctx.createOscillator();
|
||||||
const gain = ctx.createGain();
|
const gain = ctx.createGain();
|
||||||
|
const filter = ctx.createBiquadFilter();
|
||||||
|
|
||||||
|
osc.type = oscType;
|
||||||
|
osc.frequency.setValueAtTime(hz, startTime);
|
||||||
|
|
||||||
|
filter.type = 'lowpass';
|
||||||
|
filter.frequency.setValueAtTime(filterFreq, startTime);
|
||||||
|
filter.Q.setValueAtTime(1, startTime);
|
||||||
|
|
||||||
|
gain.gain.setValueAtTime(volume, startTime);
|
||||||
|
|
||||||
|
osc.connect(filter).connect(gain).connect(ctx.destination);
|
||||||
|
|
||||||
|
return { osc, gain };
|
||||||
|
};
|
||||||
|
|
||||||
osc.type = type;
|
const playSound = (
|
||||||
osc.frequency.setValueAtTime(freq, ctx.currentTime);
|
freq: number,
|
||||||
|
type: OscillatorType,
|
||||||
|
duration: number,
|
||||||
|
vol: number,
|
||||||
|
fade: boolean = false,
|
||||||
|
useFilter: boolean = false,
|
||||||
|
filterFreq: number = 800
|
||||||
|
) => {
|
||||||
|
const ctx = getAudioCtx();
|
||||||
|
const startTime = ctx.currentTime;
|
||||||
|
|
||||||
gain.gain.setValueAtTime(vol, ctx.currentTime);
|
if (useFilter) {
|
||||||
if (fade) {
|
const { osc, gain } = createFilteredOscillator(ctx, startTime, freq, vol, type, filterFreq);
|
||||||
gain.gain.exponentialRampToValueAtTime(0.0001, ctx.currentTime + duration);
|
if (fade) {
|
||||||
|
gain.gain.exponentialRampToValueAtTime(0.0001, startTime + duration);
|
||||||
|
}
|
||||||
|
osc.start(startTime);
|
||||||
|
osc.stop(startTime + duration);
|
||||||
|
} else {
|
||||||
|
const osc = ctx.createOscillator();
|
||||||
|
const gain = ctx.createGain();
|
||||||
|
|
||||||
|
osc.type = type;
|
||||||
|
osc.frequency.setValueAtTime(freq, startTime);
|
||||||
|
gain.gain.setValueAtTime(vol, startTime);
|
||||||
|
|
||||||
|
if (fade) {
|
||||||
|
gain.gain.exponentialRampToValueAtTime(0.0001, startTime + duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
osc.connect(gain).connect(ctx.destination);
|
||||||
|
osc.start(startTime);
|
||||||
|
osc.stop(startTime + duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
osc.connect(gain);
|
|
||||||
gain.connect(ctx.destination);
|
|
||||||
|
|
||||||
osc.start();
|
|
||||||
osc.stop(ctx.currentTime + duration);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// White noise (for 8-bit style noise)
|
// White noise (for 8-bit style noise)
|
||||||
@@ -62,8 +106,8 @@ export function RetroSoundTest() {
|
|||||||
|
|
||||||
// Play sound repeatedly with random delays
|
// Play sound repeatedly with random delays
|
||||||
const playRepeating = () => {
|
const playRepeating = () => {
|
||||||
// Play the sound
|
// Play the sound - triangle wave with low-pass filter for dull, machine-like tone
|
||||||
playSound(1000, 'sawtooth', 0.08, 0.1);
|
playSound(1000, 'triangle', 0.08, 0.1, false, true, 800);
|
||||||
playNoise(0.09, 0.02);
|
playNoise(0.09, 0.02);
|
||||||
|
|
||||||
// Schedule next play with random delay (0-1000ms)
|
// Schedule next play with random delay (0-1000ms)
|
||||||
@@ -96,72 +140,143 @@ export function RetroSoundTest() {
|
|||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// Crew Bailout Alarm - 90s style aggressive buzzer
|
// Beep composer - creates sequential beeps with automatic timing
|
||||||
const crewBailout = (durationSeconds: number) => {
|
const createBeepSequence = () => {
|
||||||
const ctx = getAudioCtx();
|
const ctx = getAudioCtx();
|
||||||
const startTime = ctx.currentTime;
|
let currentTime = ctx.currentTime;
|
||||||
const endTime = startTime + durationSeconds;
|
|
||||||
|
|
||||||
// Timing constants
|
return {
|
||||||
const beepDuration = 0.06; // 60ms ON
|
beep: (
|
||||||
const pauseDuration = 0.06; // 60ms OFF
|
hz: number,
|
||||||
const cycleDuration = beepDuration + pauseDuration; // 120ms total ~ 8 beeps/sec
|
duration: number,
|
||||||
|
fade: boolean = false,
|
||||||
const oscillators: OscillatorNode[] = [];
|
autoOffset: boolean = true,
|
||||||
const gainNodes: GainNode[] = [];
|
oscType: OscillatorType = 'triangle',
|
||||||
|
volume: number = 0.12,
|
||||||
let currentTime = startTime;
|
filterFreq: number = 800,
|
||||||
|
addNoise: boolean = false
|
||||||
// Generate beeps for the entire duration
|
) => {
|
||||||
while (currentTime < endTime) {
|
const { osc, gain } = createFilteredOscillator(ctx, currentTime, hz, volume, oscType, filterFreq);
|
||||||
// Create two oscillators for beating effect
|
|
||||||
const osc1 = ctx.createOscillator();
|
if (fade) {
|
||||||
const osc2 = ctx.createOscillator();
|
gain.gain.exponentialRampToValueAtTime(0.0001, currentTime + duration);
|
||||||
const gain = ctx.createGain();
|
}
|
||||||
|
|
||||||
|
osc.start(currentTime);
|
||||||
|
osc.stop(currentTime + duration + 0.05);
|
||||||
|
|
||||||
|
// Add vintage noise/hiss for realism
|
||||||
|
if (addNoise) {
|
||||||
|
const noiseBufferSize = ctx.sampleRate * duration;
|
||||||
|
const noiseBuffer = ctx.createBuffer(1, noiseBufferSize, ctx.sampleRate);
|
||||||
|
const noiseOutput = noiseBuffer.getChannelData(0);
|
||||||
|
|
||||||
|
for (let i = 0; i < noiseBufferSize; i++) {
|
||||||
|
noiseOutput[i] = (Math.random() * 2 - 1) * 0.02; // Low-level noise
|
||||||
|
}
|
||||||
|
|
||||||
|
const noiseSource = ctx.createBufferSource();
|
||||||
|
noiseSource.buffer = noiseBuffer;
|
||||||
|
|
||||||
|
const noiseGain = ctx.createGain();
|
||||||
|
noiseGain.gain.setValueAtTime(0.8, currentTime);
|
||||||
|
|
||||||
|
noiseSource.connect(noiseGain).connect(ctx.destination);
|
||||||
|
noiseSource.start(currentTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (autoOffset) currentTime += duration;
|
||||||
|
return currentTime;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Multi-tone beep (plays multiple frequencies simultaneously)
|
||||||
|
multiBeep: (
|
||||||
|
frequencies: number[],
|
||||||
|
duration: number,
|
||||||
|
fade: boolean = false,
|
||||||
|
autoOffset: boolean = true,
|
||||||
|
oscType: OscillatorType | OscillatorType[] = 'square',
|
||||||
|
volume: number = 0.08,
|
||||||
|
filterFreq: number = 1200,
|
||||||
|
addNoise: boolean = true
|
||||||
|
) => {
|
||||||
|
// Play multiple oscillators at once
|
||||||
|
frequencies.forEach((hz, index) => {
|
||||||
|
const vol = volume * (index === 0 ? 1 : 0.7); // First tone louder
|
||||||
|
const type = Array.isArray(oscType) ? oscType[index] || oscType[0] : oscType;
|
||||||
|
const { osc, gain } = createFilteredOscillator(ctx, currentTime, hz, vol, type, filterFreq);
|
||||||
|
|
||||||
|
if (fade) {
|
||||||
|
gain.gain.exponentialRampToValueAtTime(0.0001, currentTime + duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
osc.start(currentTime);
|
||||||
|
osc.stop(currentTime + duration + 0.05);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add noise
|
||||||
|
if (addNoise) {
|
||||||
|
const noiseBufferSize = ctx.sampleRate * duration;
|
||||||
|
const noiseBuffer = ctx.createBuffer(1, noiseBufferSize, ctx.sampleRate);
|
||||||
|
const noiseOutput = noiseBuffer.getChannelData(0);
|
||||||
|
|
||||||
|
for (let i = 0; i < noiseBufferSize; i++) {
|
||||||
|
noiseOutput[i] = (Math.random() * 2 - 1) * 0.006; // Much quieter vintage hiss
|
||||||
|
}
|
||||||
|
|
||||||
|
const noiseSource = ctx.createBufferSource();
|
||||||
|
noiseSource.buffer = noiseBuffer;
|
||||||
|
|
||||||
|
const noiseGain = ctx.createGain();
|
||||||
|
noiseGain.gain.setValueAtTime(0.3, currentTime); // Reduced from 1.0
|
||||||
|
|
||||||
|
noiseSource.connect(noiseGain).connect(ctx.destination);
|
||||||
|
noiseSource.start(currentTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (autoOffset) currentTime += duration;
|
||||||
|
return currentTime;
|
||||||
|
},
|
||||||
|
|
||||||
osc1.type = 'square';
|
gap: (duration: number) => {
|
||||||
osc2.type = 'square';
|
currentTime += duration;
|
||||||
osc1.frequency.setValueAtTime(2850, currentTime);
|
return currentTime;
|
||||||
osc2.frequency.setValueAtTime(2855, currentTime); // 5Hz difference for beating
|
},
|
||||||
|
|
||||||
// Envelope
|
getTime: () => currentTime,
|
||||||
const attackTime = 0.002; // 2ms attack
|
setTime: (time: number) => { currentTime = time; }
|
||||||
const releaseTime = 0.01; // 10ms release
|
};
|
||||||
|
};
|
||||||
// Attack
|
|
||||||
gain.gain.setValueAtTime(0, currentTime);
|
// Patlabor notification pattern - authentic multi-tone from spectrum analysis
|
||||||
gain.gain.linearRampToValueAtTime(0.15, currentTime + attackTime);
|
const patlaborPattern = () => {
|
||||||
|
const seq = createBeepSequence();
|
||||||
// Sustain
|
// Timing from spectrogram: 0.8s beep, 0.1s gap, 0.8s beep, 0.1s gap, 1.5s beep
|
||||||
gain.gain.setValueAtTime(0.15, currentTime + beepDuration - releaseTime);
|
seq.multiBeep([1000, 3000], 0.7, false, true, 'sawtooth'); // First beep with dual tones
|
||||||
|
seq.multiBeep([800, 2500], 0.35, false, true, 'sawtooth');
|
||||||
// Release
|
seq.multiBeep([1000, 3000], 0.7, false, true, 'sawtooth');
|
||||||
gain.gain.linearRampToValueAtTime(0, currentTime + beepDuration);
|
seq.multiBeep([800, 2500], 0.35, false, true, 'sawtooth');
|
||||||
|
seq.multiBeep([1000, 3000], 2.85, false, true, 'sawtooth');
|
||||||
// Connect nodes
|
};
|
||||||
osc1.connect(gain);
|
|
||||||
osc2.connect(gain);
|
// Custom demo pattern (high-low-high with square waves)
|
||||||
gain.connect(ctx.destination);
|
const customPattern = () => {
|
||||||
|
const seq = createBeepSequence();
|
||||||
// Start and stop
|
seq.beep(1400, 0.6, false, true, 'square');
|
||||||
osc1.start(currentTime);
|
seq.gap(0.2);
|
||||||
osc2.start(currentTime);
|
seq.beep(700, 0.6, false, true, 'square');
|
||||||
osc1.stop(currentTime + beepDuration);
|
seq.gap(0.2);
|
||||||
osc2.stop(currentTime + beepDuration);
|
seq.beep(1400, 1.0, true, true, 'square');
|
||||||
|
};
|
||||||
// Store for cleanup
|
|
||||||
oscillators.push(osc1, osc2);
|
// Rising beeps sweep
|
||||||
gainNodes.push(gain);
|
const risingBeeps = () => {
|
||||||
|
for (let i = 0; i < 8; i++) {
|
||||||
// Move to next beep
|
setTimeout(() => {
|
||||||
currentTime += cycleDuration;
|
playSound(1800 + i * 50, 'square', 0.03, 0.08);
|
||||||
|
playNoise(0.03, 0.015);
|
||||||
|
}, i * 40);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup after completion
|
|
||||||
setTimeout(() => {
|
|
||||||
oscillators.forEach(osc => osc.disconnect());
|
|
||||||
gainNodes.forEach(gain => gain.disconnect());
|
|
||||||
}, durationSeconds * 1000 + 100);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -176,71 +291,12 @@ export function RetroSoundTest() {
|
|||||||
<h3 style={{ margin: '0 0 10px 0' }}>Preset Sound</h3>
|
<h3 style={{ margin: '0 0 10px 0' }}>Preset Sound</h3>
|
||||||
<button
|
<button
|
||||||
style={{ padding: '10px 20px', backgroundColor: '#7f8c8d', color: 'white', border: 'none', borderRadius: '4px', cursor: 'pointer', fontWeight: 'bold' }}
|
style={{ padding: '10px 20px', backgroundColor: '#7f8c8d', color: 'white', border: 'none', borderRadius: '4px', cursor: 'pointer', fontWeight: 'bold' }}
|
||||||
onClick={() => {
|
onClick={risingBeeps}
|
||||||
for (let i = 0; i < 8; i++) {
|
|
||||||
setTimeout(() => {
|
|
||||||
playSound(1800 + i * 50, 'square', 0.03, 0.08);
|
|
||||||
playNoise(0.03, 0.015);
|
|
||||||
}, i * 40);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
RISING BEEPS (sweep)
|
RISING BEEPS (sweep)
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Crew Bailout Alarm - 90s Style */}
|
|
||||||
<div style={{ marginTop: '20px', padding: '15px', backgroundColor: '#c0392b', borderRadius: '8px' }}>
|
|
||||||
<h3 style={{ margin: '0 0 10px 0', color: 'white' }}>🚨 Crew Bailout Alarm (90s)</h3>
|
|
||||||
<p style={{ fontSize: '12px', color: 'white', margin: '0 0 10px 0' }}>
|
|
||||||
Agresivní mechanický bzučák: 2850 Hz + 2855 Hz square, 8 beeps/sec
|
|
||||||
</p>
|
|
||||||
<div style={{ display: 'flex', gap: '10px', flexWrap: 'wrap' }}>
|
|
||||||
<button
|
|
||||||
style={{
|
|
||||||
padding: '10px 20px',
|
|
||||||
backgroundColor: '#a93226',
|
|
||||||
color: 'white',
|
|
||||||
border: '2px solid white',
|
|
||||||
borderRadius: '4px',
|
|
||||||
cursor: 'pointer',
|
|
||||||
fontWeight: 'bold'
|
|
||||||
}}
|
|
||||||
onClick={() => crewBailout(2)}
|
|
||||||
>
|
|
||||||
⚠️ 2 sekundy
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
style={{
|
|
||||||
padding: '10px 20px',
|
|
||||||
backgroundColor: '#922b21',
|
|
||||||
color: 'white',
|
|
||||||
border: '2px solid white',
|
|
||||||
borderRadius: '4px',
|
|
||||||
cursor: 'pointer',
|
|
||||||
fontWeight: 'bold'
|
|
||||||
}}
|
|
||||||
onClick={() => crewBailout(5)}
|
|
||||||
>
|
|
||||||
🚨 5 sekund
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
style={{
|
|
||||||
padding: '10px 20px',
|
|
||||||
backgroundColor: '#7b241c',
|
|
||||||
color: 'white',
|
|
||||||
border: '2px solid white',
|
|
||||||
borderRadius: '4px',
|
|
||||||
cursor: 'pointer',
|
|
||||||
fontWeight: 'bold'
|
|
||||||
}}
|
|
||||||
onClick={() => crewBailout(10)}
|
|
||||||
>
|
|
||||||
💀 10 sekund
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Repeating Sound Toggle */}
|
{/* Repeating Sound Toggle */}
|
||||||
<div style={{ marginTop: '20px', padding: '15px', backgroundColor: isRepeating ? '#e74c3c' : '#27ae60', borderRadius: '8px' }}>
|
<div style={{ marginTop: '20px', padding: '15px', backgroundColor: isRepeating ? '#e74c3c' : '#27ae60', borderRadius: '8px' }}>
|
||||||
<h3 style={{ margin: '0 0 10px 0', color: 'white' }}>🔁 Test</h3>
|
<h3 style={{ margin: '0 0 10px 0', color: 'white' }}>🔁 Test</h3>
|
||||||
@@ -259,22 +315,43 @@ export function RetroSoundTest() {
|
|||||||
>
|
>
|
||||||
{isRepeating ? '⏹ STOP' : '▶ START'} Random Buzzer
|
{isRepeating ? '⏹ STOP' : '▶ START'} Random Buzzer
|
||||||
</button>
|
</button>
|
||||||
<h3 style={{ margin: '0 0 10px 0', color: 'white' }}>Patlabor notify effect</h3>
|
<h3 style={{ margin: '15px 0 10px 0', color: 'white' }}>🤖 Patlabor Notify Pattern</h3>
|
||||||
<button
|
<p style={{ fontSize: '12px', color: 'white', margin: '0 0 10px 0' }}>
|
||||||
style={{
|
0.8s → 0.1s gap → 0.8s → 0.1s gap → 1.5s | 1000Hz+3000Hz | Total: 3.3s
|
||||||
padding: '12px 24px',
|
</p>
|
||||||
backgroundColor: isRepeating ? '#c0392b' : '#229954',
|
<div style={{ display: 'flex', gap: '10px', flexWrap: 'wrap' }}>
|
||||||
color: 'white',
|
<button
|
||||||
border: '2px solid blue',
|
style={{
|
||||||
borderRadius: '4px',
|
padding: '12px 24px',
|
||||||
cursor: 'pointer',
|
backgroundColor: '#1e5a8e',
|
||||||
fontWeight: 'bold',
|
color: 'white',
|
||||||
fontSize: '16px'
|
border: '2px solid #3498db',
|
||||||
}}
|
borderRadius: '4px',
|
||||||
onClick={() => playSound(380, 'square', 0.1, 0.1)}
|
cursor: 'pointer',
|
||||||
>
|
fontWeight: 'bold',
|
||||||
Patlabor Notify
|
fontSize: '16px'
|
||||||
</button>
|
}}
|
||||||
|
onClick={patlaborPattern}
|
||||||
|
>
|
||||||
|
🔔 Pattern Notify
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
style={{
|
||||||
|
padding: '12px 24px',
|
||||||
|
backgroundColor: '#2e7d32',
|
||||||
|
color: 'white',
|
||||||
|
border: '2px solid #4caf50',
|
||||||
|
borderRadius: '4px',
|
||||||
|
cursor: 'pointer',
|
||||||
|
fontWeight: 'bold',
|
||||||
|
fontSize: '16px'
|
||||||
|
}}
|
||||||
|
onClick={customPattern}
|
||||||
|
>
|
||||||
|
🎵 Custom Pattern
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Raw Noise Test */}
|
{/* Raw Noise Test */}
|
||||||
@@ -286,10 +363,10 @@ export function RetroSoundTest() {
|
|||||||
key={freq}
|
key={freq}
|
||||||
style={{ padding: '8px 15px', backgroundColor: '#34495e', color: 'white', border: 'none', borderRadius: '4px' }}
|
style={{ padding: '8px 15px', backgroundColor: '#34495e', color: 'white', border: 'none', borderRadius: '4px' }}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
playSound(freq, 'sawtooth', 2, 0.1);
|
playSound(freq, 'triangle', 2, 0.1, false, true, 800);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{freq} Hz
|
{freq} Hz triangle+filter
|
||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user