Announcing purescript-wags: a library for rendering web audio
Tags: javascript, functional, webaudio
Published: 2021-04-14 13:36:04

---
title: Announcing purescript-wags: a library for rendering web audio
published: true
description: Meet the successor to purescript-audio-behaviors!
tags: javascript, functional, webaudio
cover_image: https://images.unsplash.com/photo-1605648916319-cf082f7524a1?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1350&q=80
---

I'm thrilled to announce the successor to `purescript-audio-behaviors`: [**`purescript-wags`**](https://github.com/mikesol/purescript-wags). WAGS is short for "Web Audio Graphs as a Stream", and stream-based computation is at the heart of its design.

# Why another library?

When I created [`purescript-audio-behaviors`](https://github.com/mikesol/purescript-audio-behaviors), it suffered from three issues from the get-go.

1. It didn't render audio fast enough, causing audible jank and laggy instruments.
2. It required giving each audio unit a tag, which made the code suffer from the same problem as all [stringly-typed APIs](https://wiki.c2.com/?StringlyTyped).
3. Complex feedback loops were impossible to achieve.

The second two problems were livable, but the first one proved to be really annoying. There were too many clicks, stutters, pops and lags. Responsive instruments were impossible to create, and I had to slow down the rendering engine in all but the most trivial works, which made attacks and releases less crisp.

The library's fundamental problem was that it needed to do multiple graph traversals, whereas any real rendering engine has a YOLO philosophy that avoids needless computations. Over the past month, I embarked on a new adventure: creating a second library from the ground-up, aka [**`purescript-wags`**](https://github.com/mikesol/purescript-wags).

# Show me the sound!

Here is some sound made with `purescript-wags`.

| Name | Code | Sound |
| ---- | ---- | ----- |
| Hello world | [code](https://github.com/mikesol/purescript-wags/tree/main/examples/hello-world) | [sound](https://purescript-wags-hello-world.surge.sh/) |
| Atari speaks | [code](https://github.com/mikesol/purescript-wags/tree/main/examples/atari-speaks) | [sound](https://purescript-wags-atari-speaks.surge.sh/) |
| The Well-Typed Klavier | [code](https://github.com/mikesol/purescript-wags/tree/main/examples/wtk) | [sound](https://twitter.com/stronglynormal/status/1382221415802408960) |

# How it works

Under the hood, `purescript-wags` uses a combination of [Functional Reactive Programming](https://en.wikipedia.org/wiki/Functional_reactive_programming), [Type-Level Programming](https://thinkingwithtypes.com/), [Linear types](https://en.wikipedia.org/wiki/Substructural_type_system) and [comonads](https://bartoszmilewski.com/2017/01/02/comonads/) to achieve ultra-fast web audio rendering.

Over the next few months, I'll do my best to write up articles on the points below, all of which contribute to the library in one way or another.

- a [`MemoizedState`](https://github.com/mikesol/purescript-wags/blob/main/src/WAGS/Control/MemoizedState.purs) monad that is conceptually close to the `Env` comonad
- simulated linear types using a [proof system](https://github.com/mikesol/purescript-wags/blob/3d67a3c100aaa72f0bb23f10c1714e56483a1cd9/src/WAGS/Control/Functions.purs#L152)
- [inductive types using typelevel Peanos](https://github.com/mikesol/purescript-wags/blob/3d67a3c100aaa72f0bb23f10c1714e56483a1cd9/src/WAGS/Change.purs#L465) to efficiently represent changing audio
- the use of [typeclasses for overloaded audio unit constructors](https://github.com/natefaubion/purescript-convertable-options)
- type-level lenses into audio graphs (ie [creating audio](https://github.com/mikesol/purescript-wags/blob/main/src/WAGS/Create.purs), [connecting audio] (https://github.com/mikesol/purescript-wags/blob/main/src/WAGS/Connect.purs), [disconnecting audio] (https://github.com/mikesol/purescript-wags/blob/main/src/WAGS/Disconnect.purs), etc).
- [indexed applicative functors](https://github.com/mikesol/purescript-wags/blob/main/src/WAGS/Control/Qualified.purs)
- [indexed cofree comonads](https://github.com/mikesol/purescript-wags/blob/3d67a3c100aaa72f0bb23f10c1714e56483a1cd9/src/WAGS/Control/Functions.purs#L57)
- [bitwise arithmetic in the type system](https://github.com/mikesol/purescript-wags/blob/main/src/WAGS/Universe/Bin.purs)
- type-level loops using [rebasing](https://github.com/mikesol/purescript-wags/blob/main/src/WAGS/Rebase.purs)
- [Using events and behaviors](https://github.com/mikesol/purescript-wags/blob/3d67a3c100aaa72f0bb23f10c1714e56483a1cd9/src/WAGS/Run.purs#L132) for JIT scheduling
- the [Well-Typed Klavier](https://github.com/mikesol/purescript-wags/tree/main/examples/wtk), which was the reason I started this whole thing.

I hope you make some great web-art with `purescript-wags`! If you have any questions, please don't hesitate to ask on this page or on the GitHub repo 🎹🎤🎼🔊.