I work in a building with no HVAC,
- which means we can hear everything people are saying,
- anywhere in the building.
-
-
This page is a low-CPU noise generator that runs entirely in JavaScript.
- Once it starts,
- you donโt need an Internet connection to keep it going.
- You can leave it running forever, if you like.
-
-
For those interested,
- it uses the new (in 2017) and seriously perfect for this application
- Web Audio API.
-
-
-
+This page is a low-CPU noise generator that runs entirely in JavaScript.
+Once it starts,
+you donโt need an Internet connection to keep it going.
+You can leave it running forever, if you like.
+For those interested,
+it uses the new (in 2017) and seriously perfect for this application
+[Web Audio API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API)
diff --git a/toys/starship/manifest.json b/toys/starship/manifest.json
new file mode 100644
index 0000000..58ad8a3
--- /dev/null
+++ b/toys/starship/manifest.json
@@ -0,0 +1,15 @@
+{
+ "name": "Starship Noise Generator",
+ "short_name": "Starship",
+ "start_url": ".",
+ "display": "standalone",
+ "background_color": "#fff",
+ "description": "Generates brown noise similar to a futuristic starship engine (or a modern HVAC system)",
+ "icons": [
+ {
+ "src": "icon.svg",
+ "sizes": "any"
+ }
+ ]
+}
+
diff --git a/toys/starship/starship.js b/toys/starship/starship.js
new file mode 100644
index 0000000..c236c98
--- /dev/null
+++ b/toys/starship/starship.js
@@ -0,0 +1,62 @@
+function whiteNoise(audioCtx) {
+ var bufferSize = 17 * audioCtx.sampleRate,
+ noiseBuffer = audioCtx.createBuffer(1, bufferSize, audioCtx.sampleRate),
+ output = noiseBuffer.getChannelData(0);
+ for (var i = 0; i < bufferSize; i++) {
+ output[i] = Math.random() * 2 - 1;
+ }
+ var whiteNoise = audioCtx.createBufferSource();
+ whiteNoise.buffer = noiseBuffer;
+ whiteNoise.loop = true;
+ whiteNoise.start(0);
+ return whiteNoise;
+}
+
+function bandpassFilter(audioCtx, freq, gain) {
+ var filt = audioCtx.createBiquadFilter();
+ filt.type = "bandpass";
+ filt.frequency.value = freq;
+ filt.gain.value = gain;
+ return filt;
+}
+
+function init() {
+ var audioCtx = new window.AudioContext();
+ var synth = whiteNoise(audioCtx);
+ var filterA = bandpassFilter(audioCtx, 100, 20);
+ var filterB = bandpassFilter(audioCtx, 50, 20);
+ var gainA = audioCtx.createGain();
+
+ whiteNoise(audioCtx).connect(filterA);
+ filterA.connect(filterB);
+ filterB.connect(gainA);
+ gainA.connect(audioCtx.destination);
+ audioCtx.suspend();
+
+ function setFade() {
+ var faderPos = document.querySelector("#fader").value;
+ gainA.gain.value = faderPos;
+ }
+ document.querySelector("#fader").addEventListener("input", setFade);
+ setFade();
+
+ document.querySelector("#play").addEventListener("click", e => {
+ if (audioCtx.state == "running") {
+ audioCtx.suspend();
+ } else {
+ audioCtx.resume();
+ }
+ });
+
+ console.log(navigator.serviceWorker);
+ console.log("moo");
+ if ("serviceWorker" in navigator) {
+ navigator.serviceWorker.register("sw.js");
+ }
+}
+
+if (document.readyState === "loading") {
+ document.addEventListener("DOMContentLoaded", init);
+} else {
+ init();
+}
diff --git a/toys/starship/sw.js b/toys/starship/sw.js
new file mode 100644
index 0000000..c464415
--- /dev/null
+++ b/toys/starship/sw.js
@@ -0,0 +1,26 @@
+var cacheName = "starship-v1";
+var content = [
+ "index.html",
+ "starship.js"
+];
+
+
+self.addEventListener("install", e => {
+ e.waitUntil(caches.Open(cacheName).then(cache => cache.addAll(content)));
+});
+
+// Have mercy, this is a horror show
+self.addEventListener("fetch", e => {
+ e.respondWith(
+ caches.match(e.request).then(r => {
+ console.log("[Service Worker] Fetching resource:", e.request.url);
+ return r || fetch(e.request).then(response => {
+ return caches.open(cacheName).then(cache => {
+ console.log("[Service Worker] Caching new resource:", e.request.url);
+ cache.put(e.request, respone.clone());
+ return response;
+ });
+ });
+ })
+ );
+});
\ No newline at end of file