Annoudio

An audio annotation widget that a site embeds. Members of a community tell stories about parts of a recording, and visitors see them on the organisation's own site.

Annoudio is a tool for audio annotation. A member selects a part of a recording and tells a story about it. The story can have text, a voice note, a photo or a video. You read each story and publish it. Then visitors see it in the widget on your site, on the timeline of the recording. Annoudio keeps each story as a W3C Web Annotation, so other archive tools can read it.

Who it is for

The words

The W3C Web Annotation Data Model (WADM) says: "this body says something about this target". Annoudio uses the model as it is, and gives each part a plain name. The left column is the W3C word; the middle column is the word that people read in Annoudio.

In audio annotation (W3C) In Annoudio One-line definition for a person
Annotation (type: Annotation) Story A note that a member makes about one part of a recording.
Target source (the audio resource) Recording One audio work that your organisation keeps, with a title and an audio address.
Target selector (FragmentSelector, Media Fragments t=62,95) Time range The part of the recording that the story is about, for example 1:02–1:35.
Body: TextualBody The story's text What the member writes: what they remember or hear.
Body: Sound, Image, Video (external resource) Voice note, photo, video A file that the member adds to the text of the story.
Body: TextualBody with rdf:predicate (vocab-C) Answers The member's answers to your questions, for example "Place: North landing".
Motivation commenting Story The member says something about a time range.
Motivation replying (target = another annotation) Reply A note about a story, not about the recording. One level deep.
Purpose tagging (body points at a SKOS concept) An item from a list, for example from Topics A word from your list that says what the moment is about.
creator Member The person who told the story. Visitors see the member's name, never the email.
Container (Web Annotation Protocol, LDP) The stories of a recording in a project (code: instance) All the stories that one widget shows.
A client that shows annotations Widget The element on your site that plays the recording and shows its stories.
(none: Annoudio only) Snippet The two lines that you paste into a page to show a widget.
Target scope Project The settings for one site: the lists, the look, the review rule and the rights line.
rights Rights line The licence of the stories, shown under them in one sentence.
SKOS concept scheme List (Topics, Places, Speakers) A set of items that members can choose from.
SKOS concept Item One entry in a list, with a label and a fixed address.
Property (SHACL sh:path, dcterms:spatial) Question One fact that you ask members about each story, for example "Place".
Vocabulary (ontology, schema) Questions and lists All the questions and lists of one project. A file is optional, under Advanced.
(none: WADM has no state) Review state: Processing, Waiting for review, Returned, Published Where a story is on its way from the member to the visitors.

See it work

Three of the nineteen recordings, made on the demo stack: a member tells a story on a phone, an operator publishes a story, a visitor reads it on the site.

10 · Tell a story

From the WordPress page: Tell a story, invite code, name, drag a range, answer, Send for review Member (phone) · 36.1 s · 0.57 MB · 390×844 · no sound

On the WordPress demo page (phone), the member selects Tell a story in the widget. The Annotate page asks to sign in: Have an invite code?, an email and a code from the operator (typed in lower case with a space: case, spaces and the hyphen do not matter). First sign-in: the name "Asha". On the form, a drag on the waveform marks the range and the fields follow; the story text; the answers Place = North landing and Topics = Horn; Send for review. The Start and End fields sit right under the waveform, with Use current time (0:00). The browser goes back to the WordPress page, and the widget says "Your story is sent. It shows here after review."

06 · Review publish

Review stories → a waiting story → chips → Publish dialog with preview → the next story opens Operator · 24.2 s · 0.52 MB · 1280×800 · no sound

Review stories lists the waiting stories, oldest first. Every row has its state badge. The operator opens the oldest waiting story (an earlier voice note by Asha): the chips (member, project, recording), the answers and "Told on localhost:8091". Publish opens the dialog "Publish this story?" with the story as visitors will see it; Publish the story shows "Published. Visitors see it within one minute." and the next waiting story opens.

14 · Widget

The WordPress page: play, open a story, its answers, the thread, Tell a story Visitor · 26.6 s · 0.46 MB · 1280×800 · no sound

A visitor on the WordPress demo page: Play plays the recording and the time ranges light up. Selecting Asha's story plays its range and shows its answers ("Place: North landing" and the tag Horn). Leela's story opens its thread with the reply of video 13 (published by the operator off camera). Tell a story sits under the controls; the rights line is at the end of the list.

How to run it

One organisation runs one copy: one stack of three parts (the app, Postgres and a worker), with Docker Compose.

On your computer, to change the code

docker compose -f deploy/docker-compose.dev.yml up -d --wait   # Postgres
cd app && cp .env.example .env && pnpm install && pnpm dev   # then open http://localhost:3000/admin

Set the values in app/.env first; app/README.md tells each one. A ready demo with data and a mailbox: deploy/DEMO.md.

On a server, with Dokploy (recommended)

For an organisation on its own server, with screens for backup and restore. You need a server with 4 GB of memory, a domain, an SMTP account and an S3 bucket. Read Run Annoudio with Dokploy.

On a server, with Coolify

For an organisation that already uses Coolify. It has fewer backup screens for a compose stack. Read Run Annoudio with Coolify.

For both, also read Backup and restore and Upgrade.

The snippet

A page needs two lines to show a widget. The operator copies them from the admin. ORG is the host name of the organisation's stack.

<script async src="https://ORG/embed/v1.js"></script>
<annoudio-player project="…" recording="…" src="…"><audio controls preload="none" src="…"></audio></annoudio-player>

With real values:

<script async src="https://stories.org.example/embed/v1.js"></script>
<annoudio-player project="river-voices" recording="rec-0042"
  src="https://stories.org.example/media/rec-0042.m4a"></annoudio-player>

The rules for these lines, the attributes, the theme tokens and the events are the promise to every host site: the embed contract. WordPress and Omeka S have a plugin that writes the snippet from a recording number: WordPress block, Omeka S module.

Source and licence

The code is on GitHub: github.com/micahchoo/annoudio. It is free software under the MIT licence. The design system shows the parts of the admin and the Annotate page. Not built yet, because they need people: the team trial and the pilot on a real site. The items that no test has checked are in Not verified yet.