|
|
|
|
@@ -42,7 +42,6 @@
|
|
|
|
|
let reverb: Tone.Reverb | null = null;
|
|
|
|
|
let delay: Tone.FeedbackDelay | null = null;
|
|
|
|
|
let filter: Tone.Filter | null = null;
|
|
|
|
|
let phaser: Tone.Phaser | null = null;
|
|
|
|
|
let sequence: Tone.Sequence | null = null;
|
|
|
|
|
let gain: Tone.Gain | null = null;
|
|
|
|
|
let analyser: Tone.Analyser | null = null;
|
|
|
|
|
@@ -62,11 +61,9 @@
|
|
|
|
|
// Derived reactive values using runes with safe fallbacks
|
|
|
|
|
const bpm = $derived.by(() => {
|
|
|
|
|
const temp = temperature2m ?? 20;
|
|
|
|
|
// BPM starts at 10 for 0°C and increases with temperature
|
|
|
|
|
// Day: more energetic (2x scaling), Night: calmer (1x scaling)
|
|
|
|
|
const tempAboveZero = Math.max(0, temp);
|
|
|
|
|
const scaledBpm = isDay ? 10 + tempAboveZero * 2 : 10 + tempAboveZero;
|
|
|
|
|
return Math.max(10, Math.min(200, scaledBpm));
|
|
|
|
|
// BPM: 5 at 0°C or below, 30 at 30°C or above
|
|
|
|
|
const normalizedTemp = Math.max(0, Math.min(30, temp));
|
|
|
|
|
return 5 + (normalizedTemp / 30) * 25;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const reverbWet = $derived.by(() => {
|
|
|
|
|
@@ -88,11 +85,12 @@
|
|
|
|
|
return Math.max(0.2, Math.min(0.7, (speed / 20) * 0.5 + 0.2));
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Filter cutoff: more clouds = darker/lower frequency
|
|
|
|
|
// Filter cutoff: colder = darker/lower frequency, warmer = brighter/higher frequency
|
|
|
|
|
const filterCutoff = $derived.by(() => {
|
|
|
|
|
const cover = cloudCover ?? 30;
|
|
|
|
|
// Map cloud cover: 0% clouds = 8000Hz (bright), 100% clouds = 400Hz (dark)
|
|
|
|
|
return Math.max(400, Math.min(8000, 8000 - (cover / 100) * 7600));
|
|
|
|
|
const temp = temperature2m ?? 20;
|
|
|
|
|
// Map temperature: 0°C = 400Hz (dark), 30°C = 8000Hz (bright)
|
|
|
|
|
const normalizedTemp = Math.max(0, Math.min(30, temp));
|
|
|
|
|
return 400 + (normalizedTemp / 30) * 7600;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Filter resonance: more wind = more resonant
|
|
|
|
|
@@ -167,9 +165,11 @@
|
|
|
|
|
analyser = createAnalyser();
|
|
|
|
|
|
|
|
|
|
// Connect audio chain using .chain() for clarity
|
|
|
|
|
// Synth gets filtered based on temperature
|
|
|
|
|
synth.chain(filter, delay, reverb, gain, analyser, Tone.Destination);
|
|
|
|
|
arpSynth.chain(filter, delay, reverb, gain);
|
|
|
|
|
pingSynth.chain(filter, delay, reverb, gain);
|
|
|
|
|
// Arpeggios bypass filter - only delay and reverb
|
|
|
|
|
arpSynth.chain(delay, reverb, gain);
|
|
|
|
|
pingSynth.chain(delay, reverb, gain);
|
|
|
|
|
bassSynth.chain(delay, reverb, gain);
|
|
|
|
|
|
|
|
|
|
// Generate reverb impulse
|
|
|
|
|
@@ -432,10 +432,10 @@
|
|
|
|
|
});
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-[300px_1fr] gap-8 p-4 max-w-6xl mx-auto">
|
|
|
|
|
<div class="mx-auto grid max-w-6xl grid-cols-1 gap-8 p-4 md:grid-cols-[300px_1fr]">
|
|
|
|
|
<div class="flex flex-col gap-4">
|
|
|
|
|
<button
|
|
|
|
|
class="px-6 py-3 text-base cursor-crosshair transition-all duration-300 rounded-md border border-white/20 hover:border-white/40 disabled:opacity-50 disabled:cursor-not-allowed {isPlaying
|
|
|
|
|
class="cursor-crosshair rounded-md border border-white/20 px-6 py-3 text-base transition-all duration-300 hover:border-white/40 disabled:cursor-not-allowed disabled:opacity-50 {isPlaying
|
|
|
|
|
? 'bg-white text-black'
|
|
|
|
|
: 'bg-transparent text-white'}"
|
|
|
|
|
onclick={togglePlayback}
|
|
|
|
|
@@ -450,8 +450,8 @@
|
|
|
|
|
<p class="m-0">Humidity: {relativeHumidity2m}%</p>
|
|
|
|
|
<p class="m-0">Cloud Cover: {cloudCover}%</p>
|
|
|
|
|
<p class="m-0">Wind Speed: {windSpeed10m.toFixed(1)} m/s</p>
|
|
|
|
|
<p class="opacity-40 my-1">---</p>
|
|
|
|
|
<p class="m-0">BPM: {bpm}</p>
|
|
|
|
|
<p class="my-1 opacity-40">---</p>
|
|
|
|
|
<p class="m-0">BPM: {bpm.toFixed(2)}</p>
|
|
|
|
|
<p class="m-0">Weather Extremity: {(weatherExtremity * 100).toFixed(0)}%</p>
|
|
|
|
|
<p class="m-0">Reverb: {reverbWet.toFixed(2)}</p>
|
|
|
|
|
<p class="m-0">Delay: {delayTime} @ {delayFeedback.toFixed(2)} feedback</p>
|
|
|
|
|
|