# Knocking over Scittle with audio recordings

**URL:** https://clojureverse.org/t/knocking-over-scittle-with-audio-recordings/14708
**Category:** How to?
**Tags:** introductions
**Created:** [August 31, 2025, 12:39pm UTC](https://clojureverse.org/t/knocking-over-scittle-with-audio-recordings/14708 "2025-08-31T12:39:02Z")
**Posts on this page:** 8
**Page:** 1

<div class="post-metadata">

### Author: ![simon-brooke](https://clojureverse.org/user_avatar/clojureverse.org/simon-brooke/32/5412_2.png) [@simon-brooke](https://clojureverse.org/u/simon-brooke)
#### Post date: [August 31, 2025, 12:39pm UTC](https://clojureverse.org/t/knocking-over-scittle-with-audio-recordings/14708/1 "2025-08-31T12:39:02Z")

</div>

Hi all,

I’ve been writing Clojure as my main language since [2013](https://github.com/simon-brooke/milkwood-clj), so I’m hardly a newbie. But I’m just diving into [Michiel Borkent](https://github.com/borkdude)’s [Scittle](https://babashka.org/scittle/) (which is great fun by the way), and I’m hitting problems with interoperation with JavaScript.

I’m trying to record audio from the user’s microphone. My problem is, that although I see there’s CLJS documentation for the [MediaRecorder](https://cljdoc.org/d/clojure-interop/cljs-web-api/1.0.1/api/web.audio.MediaRecorder) object, I’m failing to access it. What I’ve got is:

````auto
        (try
          (.then (.getUserMedia (.mediaDevices js/navigator) {:audio true})
            (fn [arg] 
              (let [media-recorder (MediaRecorder. arg)
                    audio-chunks (atom [])]
                  (.start media-recorder)
                  (set! media-recorder onerror 
                    (fn [s] 
                      (.log js/console (str "Error while recording sound: " s))))
                  (.addEventListener media-recorder "dataavailable" 
                    (fn [event]
                      (.info js/console "Audio recorded...")
                      (swap! audio-chunks conj (.-data event))))
                  (set! (.-onstop media-recorder)
                    (fn [e]
                      (js/console.log "data available after MediaRecorder.stop() called.")
                      (if (> (count @audio-chunks) 0)
                        (do
                          ;; Store the blob in the student-sounds data structure
                          (swap! student-recordings assoc phrase-no
                            (js/Blob. (clj->js @audio-chunks)))
                          (enable-play-button! phrase-no))))))))
          (catch js/Error e
            (.log js/console 
                (str "Error thrown while recording sound: " (.-message e))))
          (catch :default x
                (str "Unexpected object thrown while recording " x)))
```
However, I'm getting 

```
1639 (try
1640 (.then (.getUserMedia (.mediaDevices js/navigator) {:audio true})
1641 (fn [arg] 
1642 (let [media-recorder (MediaRecorder. arg)
                                         ^--- Could not resolve symbol: MediaRecorder
1643 audio-chunks (atom [])]
1644 (.start media-recorder)
```

When I try
```
(require 'web.audio)
```

I get

```
Message: Could not find namespace: web.audio. <anonymous code>:1:145535
Location: scittle-tag-2:1:1 <anonymous code>:1:145535
----- Context ------------------------------------ <anonymous code>:1:145535

1 (require '[reagent.core :as r]
   ^--- Could not find namespace: web.audio.
2 '[reagent.dom :as rdom]
3 'web.audio)
```
I'm guessing that the web API isn't compiled into Scittle, and that what I need to do is fall back onto plain old fashioned Clojurescript.

But can anyone think how I could work around this?

````

---

<div class="post-metadata">

### Author: ![simon-brooke](https://clojureverse.org/user_avatar/clojureverse.org/simon-brooke/32/5412_2.png) [@simon-brooke](https://clojureverse.org/u/simon-brooke)
#### Post date: [August 31, 2025, 12:47pm UTC](https://clojureverse.org/t/knocking-over-scittle-with-audio-recordings/14708/2 "2025-08-31T12:47:20Z")

</div>

For examples of stuff I have got working in Scittle so far, check out these pages:

- [Turtle graphics](https://www.journeyman.cc/~simon/tmp/index.html) (quite slow, takes a while to draw)
- [Gurmukhi pronunciation lessons](https://www.journeyman.cc/~simon/tmp/japji/) (not fully working yet, that’s what the sound recorder is for)

---

<div class="post-metadata">

### Author: ![p-himik](https://clojureverse.org/user_avatar/clojureverse.org/p-himik/32/4137_2.png) [@p-himik](https://clojureverse.org/u/p-himik)
#### Post date: [August 31, 2025, 2:00pm UTC](https://clojureverse.org/t/knocking-over-scittle-with-audio-recordings/14708/3 "2025-08-31T14:00:30Z")

</div>

Have you tried `js/MediaRecorder`?

---

<div class="post-metadata">

### Author: ![simon-brooke](https://clojureverse.org/user_avatar/clojureverse.org/simon-brooke/32/5412_2.png) [@simon-brooke](https://clojureverse.org/u/simon-brooke)
#### Post date: [August 31, 2025, 4:14pm UTC](https://clojureverse.org/t/knocking-over-scittle-with-audio-recordings/14708/4 "2025-08-31T16:14:12Z")

</div>

D’oh!

I had not, and that was the right answer.

---

<div class="post-metadata">

### Author: ![timothypratley](https://clojureverse.org/user_avatar/clojureverse.org/timothypratley/32/970_2.png) [@timothypratley](https://clojureverse.org/u/timothypratley)
#### Post date: [August 31, 2025, 7:23pm UTC](https://clojureverse.org/t/knocking-over-scittle-with-audio-recordings/14708/5 "2025-08-31T19:23:10Z")

</div>

[GitHub - brianium/blah: A library for working with microphones in ClojureScript](https://github.com/brianium/blah) might be relevant for inspiration (but I don’t think it will work in Scittle)

---

<div class="post-metadata">

### Author: ![borkdude](https://clojureverse.org/user_avatar/clojureverse.org/borkdude/32/306_2.png) [@borkdude](https://clojureverse.org/u/borkdude)
#### Post date: [September 8, 2025, 9:15am UTC](https://clojureverse.org/t/knocking-over-scittle-with-audio-recordings/14708/6 "2025-09-08T09:15:16Z")

</div>

I briefly looked into this and tried with:

```auto
<script src="https://cdn.jsdelivr.net/npm/scittle@0.7.27/dist/scittle.js" type="application/javascript"></script>

<script type="application/x-scittle">
  (defn array-seq [arr] (seq arr))
  (intern 'clojure.core 'array-seq array-seq)
</script>

<script src="https://raw.githubusercontent.com/brianium/blah/refs/heads/main/src/blah/transforms.cljs" type="application/x-scittle"></script>

<script src="https://raw.githubusercontent.com/brianium/blah/refs/heads/main/src/blah/impl.cljs" type="application/x-scittle"></script>

<script src="https://raw.githubusercontent.com/brianium/blah/refs/heads/main/src/blah/core.cljs" type="application/x-scittle"></script>

```

The first thing I ran into was `array-seq` not existing in scittle, a thing that can be easily fixed. But the major problem is that cljs.core.async was used in this library and this is indeed unsupported.

---

<div class="post-metadata">

### Author: ![simon-brooke](https://clojureverse.org/user_avatar/clojureverse.org/simon-brooke/32/5412_2.png) [@simon-brooke](https://clojureverse.org/u/simon-brooke)
#### Post date: [September 29, 2025, 4:43pm UTC](https://clojureverse.org/t/knocking-over-scittle-with-audio-recordings/14708/7 "2025-09-29T16:43:19Z")

</div>

OK, I’m not completely out of the woods yet. What I have now is:

```clojure

(defn record-student-sound!
  [phrase-no]
  (.info js/console "Recording student sound for phrase " phrase-no)

  (try
    (.then (.getUserMedia (.mediaDevices js/navigator) {:audio true})
           (fn [arg]
             (let [media-recorder (js/MediaRecorder. arg)
                   audio-chunks (atom [])]
               (set! (.-onerror media-recorder)
                     (fn [s]
                       (.log js/console (str "Error while recording sound: " s))))
               (.addEventListener media-recorder "dataavailable"
                                  (fn [event]
                                    (.info js/console "Audio recorded...")
                                    (swap! audio-chunks conj (.-data event))))
               (set! (.-onstop media-recorder)
                     (fn [e]
                        (js/console.log "data available after MediaRecorder.stop() called.")
                        (when (> (count @audio-chunks) 0)
                          (swap! student-recordings assoc phrase-no
                                 (js/Blob. (clj->js @audio-chunks))))))
               (.start media-recorder))))
    (catch js/Error e
      (.log js/console
            (str "Error thrown while recording sound: " (.-message e))))
    (catch :default x
      (str "Unexpected object thrown while recording " x))))

```

What I’m getting is

```auto
Error thrown while recording sound: f is not a function

```

The message ‘Audio recorded…’ is never printed, so I’m guessing the `f` that ‘is not a function’ is the handler for `dataavailable` But I don’t understand why it isn’t, or that is needed.

---

<div class="post-metadata">

### Author: ![system](https://clojureverse.org/uploads/default/original/2X/5/51079bf9e4b7d9466242c06cf1e43b9f8bd6da14.png) [@system](https://clojureverse.org/u/system)
#### Post date: [March 31, 2026, 4:44am UTC](https://clojureverse.org/t/knocking-over-scittle-with-audio-recordings/14708/8 "2026-03-31T04:44:06Z")

</div>

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.
