Add synthesized background melody and volume slider to SubpageRain

This commit is contained in:
Felix Brabetz
2026-05-16 05:40:45 +02:00
parent eaa030d7c5
commit 845d72136d
+45 -2
View File
@@ -7,11 +7,13 @@ window.rainData = function() {
rainIntensity: 50,
wind: 0,
lofiFilter: 800,
musicVolume: 30,
drops: [],
audioCtx: null,
noiseNode: null,
filterNode: null,
gainNode: null,
melodyGain: null,
generateDrops(val) {
this.drops = [];
@@ -23,6 +25,7 @@ window.rainData = function() {
try {
this.audioCtx = new (window.AudioContext || window.webkitAudioContext)();
// --- REGEN-SOUND (Weißes Rauschen) ---
let bufferSize = 2 * this.audioCtx.sampleRate;
let noiseBuffer = this.audioCtx.createBuffer(1, bufferSize, this.audioCtx.sampleRate);
let output = noiseBuffer.getChannelData(0);
@@ -46,6 +49,40 @@ window.rainData = function() {
this.gainNode.connect(this.audioCtx.destination);
this.noiseNode.start();
// --- MELODIE-SOUND (Echte "Easy Music") ---
let melodyOsc = this.audioCtx.createOscillator();
this.melodyGain = this.audioCtx.createGain();
melodyOsc.type = 'sine';
let lowpass = this.audioCtx.createBiquadFilter();
lowpass.type = 'lowpass';
lowpass.frequency.setValueAtTime(400, this.audioCtx.currentTime); // Sehr dumpf und weich
melodyOsc.connect(lowpass);
lowpass.connect(this.melodyGain);
this.melodyGain.connect(this.audioCtx.destination);
melodyOsc.start();
// Langsame, beruhigende Pentatonik-Folge
let notes = [261.63, 329.63, 392.00, 440.00, 392.00, 329.63]; // C4, E4, G4, A4, G4, E4
let i = 0;
setInterval(() => {
let now = this.audioCtx.currentTime;
let freq = notes[i];
melodyOsc.frequency.setValueAtTime(freq, now);
// Sanftes Ein- und Ausblenden der Note
let maxVol = (this.musicVolume / 100) * 0.05;
this.melodyGain.gain.setValueAtTime(0, now);
this.melodyGain.gain.linearRampToValueAtTime(maxVol, now + 1.5);
this.melodyGain.gain.linearRampToValueAtTime(0, now + 3.5);
i = (i + 1) % notes.length;
}, 4000); // Alle 4 Sekunden eine Note
} catch(e) {
console.log('Audio failed', e);
}
@@ -66,7 +103,7 @@ window.rainData = function() {
<!-- Subpage: Rain Detail -->
<div x-show="currentPage === 'page-rain'" x-cloak x-transition:enter="transition ease-out duration-500" x-transition:enter-start="opacity-0 translate-y-4" x-transition:enter-end="opacity-100 translate-y-0" class="min-h-screen pt-28 pb-24 px-6 lg:px-8 bg-stone-950 relative overflow-hidden"
x-data="window.rainData()"
x-init="generateDrops(rainIntensity); $watch('rainIntensity', value => { generateDrops(value); updateAudio() }); $watch('lofiFilter', value => updateAudio()); $watch('currentPage', val => val === 'page-rain' && initAudio())">
x-init="generateDrops(rainIntensity); $watch('rainIntensity', value => { generateDrops(value); updateAudio() }); $watch('lofiFilter', value => updateAudio()); $watch('currentPage', val => { if(val === 'page-rain') initAudio(); })">
<!-- Rain Container (Full Screen on this page) -->
<div class="absolute inset-0 pointer-events-none z-0">
@@ -106,10 +143,16 @@ window.rainData = function() {
<label class="block text-xs font-mono text-stone-500 uppercase mb-2 tracking-widest">Lofi-Filter (Muffigkeit): <span x-text="lofiFilter" class="text-emerald-400"></span> Hz</label>
<input type="range" min="200" max="2000" x-model="lofiFilter" class="w-full h-2 bg-stone-800 rounded-lg appearance-none cursor-pointer accent-emerald-500">
</div>
<!-- Music Volume -->
<div>
<label class="block text-xs font-mono text-stone-500 uppercase mb-2 tracking-widest">Musik-Lautstärke: <span x-text="musicVolume" class="text-emerald-400"></span>%</label>
<input type="range" min="0" max="100" x-model="musicVolume" class="w-full h-2 bg-stone-800 rounded-lg appearance-none cursor-pointer accent-emerald-500">
</div>
<div class="flex justify-between text-xs text-stone-600 font-mono pt-4 border-t border-stone-800">
<span>Sound läuft automatisch</span>
<span class="text-emerald-400">Realtime Web Audio Rain</span>
<span class="text-emerald-400">Realtime Web Audio Rain & Melody</span>
</div>
</div>