Realtime Weather Sonification

OpenWeatherMap

This first, simple Web Audio sonification application makes use of the Weather API for real-time, browser-based sonification of weather data. For fetching data, a free subscription is necessary: https://home.openweathermap.org

Once subscribed, the API key can be used to get current weather information in the browser:

https://api.openweathermap.org/data/2.5/weather?q=Potsdam&appid=eab7c410674e15bfdd841f66941a92c2

JSON Data Structure

The resulting output in JSON looks like this:

{
  "coord": {
    "lon": 13.41,
    "lat": 52.52
  },
  "weather": [
    {
      "id": 804,
      "main": "Clouds",
      "description": "overcast clouds",
      "icon": "04d"
    }
  ],
  "base": "stations",
  "main": {
    "temp": 9.74,
    "feels_like": 6.57,
    "temp_min": 9,
    "temp_max": 10.56,
    "pressure": 1034,
    "humidity": 93
  },
  "visibility": 8000,
  "wind": {
    "speed": 4.1,
    "deg": 270
  },
  "clouds": {
    "all": 90
  },
  "dt": 1604655648,
  "sys": {
    "type": 1,
    "id": 1275,
    "country": "DE",
    "sunrise": 1604643143,
    "sunset": 1604676458
  },
  "timezone": 3600,
  "id": 2950159,
  "name": "Berlin",
  "cod": 200
}

All entries of this data structure can be used as synthesis parameters in a sonification system with Web Audio.

Temperatures to Frequencies

Mapping

In this example we are using a simple freuency modulation formula for turning temperature and humidity into more or less pleasing (annoying) sounds. The frequency of a first oscillator is derived from the temperature:

\(\displaystyle f_1 = 10 \frac{1}{{T^2 / C^{\circ} }}\)

The modulator frequency is controlled by the humidity \(H\):

\(y = sin(2 \pi (f_1 + 100*sin(2 \pi H t))t)\)


The Result

The resulting app fetches the weather data of a chosen city, extracts temperature and humidity and sets the parameters of the audio processes:

Where would you rather be?

What does the weather sound like in ...?


Code

weather/weather.html (Source)

<!doctype html>
<html>

<head>
<title>Where would you rather be?</title>
</head>
<blockquote style="border: 2px solid #122; padding: 10px; background-color: #ccc;">
<body>
<p>What does the weather sound like in ...?</p>
<p>
<button onclick="myFunction()">Enter City Name</button>
<button onclick="stop()">Stop</button>
<p id="demo"></p>

</p>

</body>
<div id="location"></div>
<div id="weather">
<div id="description"></div>
<h1 id="temp"></h1>
<h1 id="humidity"></h1>
</div>
</blockquote>

<script>

var audioContext = new window.AudioContext
var oscillator   = audioContext.createOscillator()
var modulator    = audioContext.createOscillator()

// the output gain
var gainNode     = audioContext.createGain()

var modInd        = audioContext.createGain();
modInd.gain.value = 100;

gainNode.gain.value = 0

modulator.connect(modInd)
modInd.connect(oscillator.detune)
oscillator.connect(gainNode)
gainNode.connect(audioContext.destination)

oscillator.start(0)
oscillator.frequency.setValueAtTime(100, audioContext.currentTime);

modulator.start(0)
modulator.frequency.setValueAtTime(100, audioContext.currentTime);

function myFunction() {
  var city = prompt("Enter City Name", "Potsdam");
  if (city != null) {
  get_weather(city)
  }
}


function stop()
{
gainNode.gain.linearRampToValueAtTime(0, audioContext.currentTime + 1);
}

function frequency(y)
{
oscillator.frequency.value = y
}

function get_weather( cityName )
{
    var key = 'eab7c410674e15bfdd841f66941a92c2';
    fetch('https://api.openweathermap.org/data/2.5/weather?q=' + cityName+ '&appid=' + key)
    .then(function(resp) { return resp.json()}) // Convert data to json
    .then(function(data) {
    setSynth(data);
    })
    .catch(function() {
    // catch any errors
    });
}

function setSynth(d)
{
    var celcius = Math.round(parseFloat(d.main.temp)-273.15);
    var fahrenheit = Math.round(((parseFloat(d.main.temp)-273.15)*1.8)+32);

    var humidity = d.main.humidity;

    oscillator.frequency.linearRampToValueAtTime(1000*(100/(celcius*celcius)), audioContext.currentTime + 1);

    modulator.frequency.linearRampToValueAtTime(humidity, audioContext.currentTime + 1);

    gainNode.gain.linearRampToValueAtTime(1, audioContext.currentTime + 1);

    document.getElementById('description').innerHTML = d.weather[0].description;
    document.getElementById('temp').innerHTML = celcius + '&deg;';
    document.getElementById('location').innerHTML = d.name;
    document.getElementById('humidity').innerHTML = 'Humidity: '+humidity;
}

</script>
</html>


Contents © Henrik von Coler 2020 - Contact