diff --git a/src/lib/audio/instruments/bassSynth.ts b/src/lib/audio/instruments/bassSynth.ts index b460b55..e13ae72 100644 --- a/src/lib/audio/instruments/bassSynth.ts +++ b/src/lib/audio/instruments/bassSynth.ts @@ -11,6 +11,6 @@ export function createBassSynth(): Tone.Synth { sustain: 0.8, release: 2.0 }, - volume: -15 + volume: -13 }); } diff --git a/src/lib/audio/instruments/padSynth.ts b/src/lib/audio/instruments/padSynth.ts index b78dccb..e7bc475 100644 --- a/src/lib/audio/instruments/padSynth.ts +++ b/src/lib/audio/instruments/padSynth.ts @@ -13,6 +13,6 @@ export function createPadSynth(isDay: boolean): Tone.PolySynth { sustain: 0.85, // Higher sustain for consistent pad presence release: isDay ? 2.5 : 4.0 // Longer release for smooth tail-off }, - volume: -16 // Quieter to sit back in the mix and reduce mid heaviness + volume: -14 // Quieter to sit back in the mix and reduce mid heaviness }); } diff --git a/src/lib/components/AudioVisualization.svelte b/src/lib/components/AudioVisualization.svelte index b368218..288a4b9 100644 --- a/src/lib/components/AudioVisualization.svelte +++ b/src/lib/components/AudioVisualization.svelte @@ -55,17 +55,22 @@ this.x += this.vx; this.y += this.vy; + // Guard against invalid values + const safeAudioLevel = isFinite(audioLevel) ? audioLevel : 0; + const safeBass = isFinite(bass) ? bass : 0; + const safeMid = isFinite(mid) ? mid : 0; + // Subtle audio reactive displacement (less frequent on mobile) const updateFrequency = isMobile ? 5 : 3; if (p.frameCount % updateFrequency === 0) { - const displacement = audioLevel * 20; + const displacement = safeAudioLevel * 20; const angle = p.noise(this.x * 0.01, this.y * 0.01, p.frameCount * 0.01) * p.TWO_PI; this.x += p.cos(angle) * displacement * 0.05; this.y += p.sin(angle) * displacement * 0.05; } // Subtle audio reactive size - this.size = p.map(bass + mid, 0, 2, 3, 10); + this.size = p.map(safeBass + safeMid, 0, 2, 3, 10); // Wrap around edges if (this.x < -50) this.x = p.width + 50; @@ -76,7 +81,8 @@ display(p: p5, audioLevel: number) { p.noStroke(); - const dynamicAlpha = p.map(audioLevel, 0, 1, 120, 220); + const safeAudioLevel = isFinite(audioLevel) ? audioLevel : 0; + const dynamicAlpha = p.map(safeAudioLevel, 0, 1, 120, 220); p.fill(255, dynamicAlpha); p.ellipse(this.x, this.y, this.size, this.size); } @@ -145,7 +151,10 @@ for (let i = 0; i < audioData.length; i++) { // Convert from decibels to linear scale (0-1) // FFT returns values from -100 to 0 dB - const normalized = p.map(audioData[i], -100, -30, 0, 1, true); + const value = audioData[i]; + // Guard against NaN/Infinity + if (!isFinite(value)) continue; + const normalized = p.map(value, -100, -30, 0, 1, true); sum += normalized; if (i < bassRange) { @@ -157,17 +166,17 @@ } } - // Average and amplify moderately - let audioLevel = (sum / audioData.length) * 2; - bass = (bass / bassRange) * 2.5; - mid = (mid / (midRange - bassRange)) * 2; - treble = (treble / (audioData.length - trebleStart)) * 1.5; + // Average and amplify moderately (with division by zero guards) + let audioLevel = audioData.length > 0 ? (sum / audioData.length) * 2 : 0; + bass = bassRange > 0 ? (bass / bassRange) * 2.5 : 0; + mid = (midRange - bassRange) > 0 ? (mid / (midRange - bassRange)) * 2 : 0; + treble = (audioData.length - trebleStart) > 0 ? (treble / (audioData.length - trebleStart)) * 1.5 : 0; - // Clamp values - audioLevel = p.constrain(audioLevel, 0, 1); - bass = p.constrain(bass, 0, 1); - mid = p.constrain(mid, 0, 1); - treble = p.constrain(treble, 0, 1); + // Clamp values to prevent NaN + audioLevel = isNaN(audioLevel) ? 0 : p.constrain(audioLevel, 0, 1); + bass = isNaN(bass) ? 0 : p.constrain(bass, 0, 1); + mid = isNaN(mid) ? 0 : p.constrain(mid, 0, 1); + treble = isNaN(treble) ? 0 : p.constrain(treble, 0, 1); // Fixed connection distance for consistency const connectionDist = 100; diff --git a/src/lib/generators/air-quality/AirQualityGen.svelte b/src/lib/generators/air-quality/AirQualityGen.svelte index d964b85..fd7be98 100644 --- a/src/lib/generators/air-quality/AirQualityGen.svelte +++ b/src/lib/generators/air-quality/AirQualityGen.svelte @@ -63,7 +63,9 @@ const delayTime = $derived.by(() => { const speed = windSpeed10m ?? 0; - return speed > 5 ? '4n' : '8n'; + // Map 0-20 m/s wind to 0.1-0.8 second delay range + const normalized = Math.min(20, speed) / 20; + return 0.1 + normalized * 0.7; }); const delayFeedback = $derived.by(() => { @@ -149,8 +151,7 @@ // Set all audio parameters once (static until page refresh) if (delay) { - const delayTimeSeconds = Tone.Time(delayTime).toSeconds(); - delay.delayTime.value = delayTimeSeconds; + delay.delayTime.value = delayTime; delay.feedback.value = delayFeedback; } diff --git a/src/lib/generators/weather/WeatherGen.svelte b/src/lib/generators/weather/WeatherGen.svelte index cde4cd5..113aa1f 100644 --- a/src/lib/generators/weather/WeatherGen.svelte +++ b/src/lib/generators/weather/WeatherGen.svelte @@ -81,10 +81,12 @@ return Math.max(0.3, Math.min(1, humidity / 100)); }); - // Delay time: 8th note for calm, quarter note for windy + // Delay time: shorter delay for calm, longer for windy (scaled to 0.1-0.8 seconds) const delayTime = $derived.by(() => { const speed = windSpeed10m ?? 0; - return speed > 5 ? '4n' : '8n'; + // Map 0-20 m/s wind to 0.1-0.8 second delay range + const normalized = Math.min(20, speed) / 20; + return 0.1 + normalized * 0.7; }); // Delay feedback: stronger with more wind @@ -245,8 +247,7 @@ } if (delay) { - const delayTimeSeconds = Tone.Time(delayTime).toSeconds(); - delay.delayTime.value = delayTimeSeconds; + delay.delayTime.value = delayTime; delay.feedback.value = delayFeedback; } @@ -516,7 +517,7 @@

BPM: {bpm.toFixed(2)}

Weather Extremity: {(weatherExtremity * 100).toFixed(0)}%

Reverb: {reverbWet.toFixed(2)}

-

Delay: {delayTime} @ {delayFeedback.toFixed(2)} feedback

+

Delay: {delayTime.toFixed(2)}s @ {delayFeedback.toFixed(2)} feedback

Filter: {Math.round(filterCutoff)}Hz Q:{filterResonance.toFixed(1)}

{/if}