A Clojurescript wrapper for the Web Audio API, extracted from Klangmeister.
CLJS Bach is a Clojurescript library. To include it in your Clojurescript project, you need to
include the following in your project.clj
or build.boot
.
Once you've done that, you can use it like any other library.
Firstly, create an audio context. You only need one, and if you keep creating them the browser will run out and error on you.
(defonce context (audio-context))
See Klangmeister for examples of how to build synthesisers. Here's a simple
one. Note the use of connect->
to join together simple parts together.
(defn ping [freq]
(connect->
(square freq) ; Try a sawtooth wave.
(percussive 0.01 0.4) ; Try varying the attack and decay.
(gain 0.1))) ; Try a bigger gain.
Once you have a synthesiser, connect it to destination
and use run-with
to give it an audio context, a time to run at
and a duration.
; Play the ping synthesiser now, at 440 hertz.
(-> (ping 440)
(connect-> destination)
(run-with context (current-time context) 1.0)))
If you forget to connect a synthesiser to destination
, then you'll here no sound, because nothing will be sent to the speakers.
See resources/public/index.html
. To try it out, run lein figwheel
and then navigate to http://localhost:3449/
.
(audio-context)
- returns the browser's Audio Context.(current-time context)
- returns the current time according to the supplied audio context.(run-with node context at duration)
- runs the synthesiser in the supplied context.destination
- a node representing the browser's speakers.
(sawtooth frequency)
- a sawtooth wave oscillating atfrequency
hertz.(sine frequency)
- a sine wave oscillating atfrequency
hertz.(square frequency)
- a square wave oscillating atfrequency
hertz.(triangle frequency)
- a triangle wave oscillating atfrequency
hertz.white-noise
- a node emitting random noise.
(adsr attack decay sustain release)
- an envelope for shaping a note.(gain level)
- a node that multiplies its input bylevel
.(high-pass cutoff)
- filter out frequencies belowcutoff
.(low-pass cutoff)
- filter out frequencies abovecutoff
.(percussive attack decay)
- a simple envelope for shaping a note.
(stereo-panner pan)
- pan the signal left (-1) or right (1).(delay-line seconds)
- delay the signal byseconds
.reverb
- apply reverb to the signal.
(connect-> node1 node2)
- connectnode1
's output tonode2
's input.(add node1 node2)
- add together the outputs ofnode1
andnode2
.
(sample uri)
- load a sample from a URI, which can then be used as a source node in the same way that oscillators can. The asynchronicity can make this a little glitchy.
CLJS Bach relies on the Web Audio API, so it will only work if your javascript environment supports that. Fortunately, all major browsers except Internet Explorer do (and it will on next major release).
If you have this project checked out locally, you can use the Figwheel REPL. Firstly, start Figwheel.
lein figwheel
Figwheel will tell you where's running, so you can open it in your browser.
Figwheel: Starting server at http://localhost:3449
....
Prompt will show when Figwheel connects to your application
Once you've done that, the REPL will come to life.
To quit, type: :cljs/quit
cljs.user=>
From then on, you can type commands into the REPL, and they'll be executed by your browser.
CLJS Bach is purely functional. To make synthesiser composition easier, synthesisers are actually functions that take an audio context, a time and a duration and return the synthesis graph.
(defn some-synth [...]
(fn [context at duration]
; Create a graph of synthesis nodes.
))
That's why you need run-with
to make sound actually happen.