Skip to content

Document .opus emote sound and add a converter for it - #27

Open
dima-dencep wants to merge 5 commits into
mainfrom
feature/emote-sound-converter
Open

Document .opus emote sound and add a converter for it#27
dima-dencep wants to merge 5 commits into
mainfrom
feature/emote-sound-converter

Conversation

@dima-dencep

@dima-dencep dima-dencep commented Sep 5, 2026

Copy link
Copy Markdown
Member

Emote sound moved from Note Block Studio to Opus, so the page that told people to open Note Block Studio needed rewriting, and the format it now describes is one nobody can produce by hand without reading a spec.

creatingmusic.md

Rewritten around putting an .opus next to the emote:

  • what .opus even is — ordinary audio, the same format Discord uses, chosen here because it stays small enough to travel inside the emote packet — and how to play one back: Windows, Linux and Android open it as is, macOS needs VLC, and dragging the file into a browser works anywhere
  • where the file goes and that the name has to match the emote
  • the LOOPSTART tag, with the ffmpeg command and the note that 48000 samples is one second
  • the limits (mono, 1 MB, 96 kbps, 10 minutes) and which one you actually run into — at 32 kbps that is about four and a half minutes
  • why you should not normalise the file yourself: the mod evens out loudness between emotes, and players can turn that off
  • Note Block Studio kept at the end as legacy. Current versions no longer play .nbs, but it is still passed through to older clients, so keeping both files next to the emote is worth explaining

/opus-converter

Making that file by hand means knowing the mod wants mono at 48 kHz and that the result has to survive a network packet. This page does it instead: drop in any audio file, choose quality, trim and looping, download something the mod accepts.

  • built as a Docusaurus page, so it gets the site theme, dark mode and navigation for free
  • mono and 48 kHz are applied without asking
  • the size is estimated before encoding, shown against the 1 MB limit, and the button is disabled with advice on what to change when it does not fit
  • the loop checkbox writes LOOPSTART so nobody has to compute a sample offset
  • the result can be previewed on the page, which for most people removes the question of what opens an .opus at all

@ffmpeg/ffmpeg and @ffmpeg/util come from npm and are imported lazily inside the click handler, so the static build never loads them. The 31 MB wasm core is fetched from a CDN rather than committed.

Checked

Ran the whole path against the production build, then fed the downloaded file to Emotecraft's own parser: mono, preSkip=312, LOOPSTART read back, 401 packets, round trip byte-identical.

Two things this turned up and fixed:

  • plain VBR overshot a 32 kbps target by 30% (42 KB where the estimate said 32 KB), which matters when the ceiling is 1 MB. Encoding is now constrained VBR, and the estimate matches.
  • <audio> never reported metadata in Chrome, so the duration comes from decodeAudioData instead — immediate and exact.

🤖 Generated with Claude Code

Emote sound moved from Note Block Studio to Opus, so creatingmusic.md now
describes putting an .opus next to the emote, the LOOPSTART tag that makes it
repeat, the limits the mod enforces, and why the file should not be normalised
by hand. Note Block Studio stays at the end: current versions no longer play
.nbs, but it is still passed through to older clients, so shipping both is
worth explaining.

Writing that file by hand means knowing that Emotecraft wants mono at 48 kHz
and that the result has to fit in a network packet, which is a lot to ask of
someone who just wants a song under their emote. /opus-converter does it in the
browser instead: drop in any audio file, pick quality, trim and looping, and
download something the mod will accept. It estimates the size before encoding
and refuses to produce a file that is over the limit.

ffmpeg.wasm does the encoding. Its wrapper comes from npm but is imported
lazily so the static build never touches it, and the 31 MB core is fetched from
a CDN rather than committed here. Encoding is constrained VBR: plain VBR
overshot a 32 kbps target by 30%, which matters when the ceiling is 1 MB.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Sep 5, 2026

Copy link
Copy Markdown

Deploying paldocs with  Cloudflare Pages  Cloudflare Pages

Latest commit: 6d8179e
Status: ✅  Deploy successful!
Preview URL: https://f2ca4977.paldocs.pages.dev
Branch Preview URL: https://feature-emote-sound-converte.paldocs.pages.dev

View logs

dima-dencep and others added 4 commits September 5, 2026 15:01
The page asked people to produce a file format they may never have seen, without
saying what it is or how to play it back. Opus is ordinary audio, the same thing
Discord uses, and it is here because it stays small enough to travel inside the
emote packet. Opening one varies by system: Windows, Linux and Android handle it
as is, macOS needs VLC, and dragging the file into a browser works everywhere.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`-ac 1` sums the two channels without halving them, so every file the converter
produced came out 6 dB hot. Anything past full scale is lost when the decoder
hands the mod int16 samples, which is heard as crackling. On a normal track that
was 2.4% of samples clipped, peaking at +5.5 dBFS.

The pan filter mixes the channels properly, and a limiter takes the overshoot
the encoder itself adds at low bitrates. Both together bring the same clip to
+1.75 dBFS with 0.037% past full scale. `level=disabled` is not optional: the
limiter otherwise restores the level it just took off.

Nothing gets quieter for it. The mod normalises every sound to the same loudness,
so a file with fewer clipped peaks is attenuated less and ends up louder.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The legacy section said .nbs is passed along without saying what to do about it.
An emote can hold both files at once: current clients get the .opus, older ones
get the .nbs, and a server hands each player whichever they can play, so one pack
covers every version. Keeping the .nbs costs a few kilobytes and is never sent to
a client that would ignore it.

Also noted that emotes from EmotecraftLibrary need none of this — it generates
the .opus for anything that has a .nbs, so downloads already carry both.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant