npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

ww2ogg-ts

v0.2.0

Published

Convert Audiokinetic Wwise RIFF/RIFX Vorbis (.wem) audio to standard Ogg Vorbis, in pure TypeScript.

Readme

ww2ogg-ts

TypeScript port of ww2ogg by Adam Gashlin (hcs).

Convert Audiokinetic Wwise RIFF/RIFX Vorbis (.wem) audio into standard Ogg Vorbis. Pure TypeScript, zero runtime dependencies, works in Node and — with a bundler — the browser. License: BSD-3-Clause.

  • In-memory core — Uint8Array in, Buffer out. No filesystem access in the library itself, so it drops into a server, a worker, or the browser.
  • No decoding — it rewrites Wwise's stripped Vorbis headers into valid Ogg Vorbis and repackages the audio packets into Ogg pages. Output is an .ogg Vorbis file; no PCM is ever produced.
  • Granule recomputation built in — duration and seeking come out correct by default, with no separate revorb step.

Table of contents


Install

npm install ww2ogg-ts

Requires Node >= 18. Ships CommonJS with TypeScript type declarations (dist/index.d.ts).

The package bundles the codebook data files under data/, so the CLI works out of the box. When you call the library directly you pass the codebook bytes in yourself (see below).


Quick start (library)

import { readFileSync, writeFileSync } from "node:fs";
import { convertWwiseRiffToOgg, getPackedCodebooks } from "ww2ogg-ts";

const wem = readFileSync("song.wem");
// Bundled with the package; loaded via the official codebooks API.
const codebooks = getPackedCodebooks();

const { ogg, info } = convertWwiseRiffToOgg(wem, { codebooks });

console.log(info);              // stream summary (channels, rate, headers, ...)
writeFileSync("song.ogg", ogg); // `ogg` is a Node Buffer

That's the whole happy path: hand it the .wem bytes plus a codebook set, get an .ogg back.


Quick start (CLI)

# installed globally or via npx
npx ww2ogg-ts song.wem              # -> song.ogg
npx ww2ogg-ts song.wem -o out.ogg   # explicit output name

If -o is omitted the output name is derived from the input (song.wem → song.ogg). The bundled standard codebooks are used unless you override them with --pcb <file>.


Codebooks: which file to use

Wwise usually strips the Vorbis codebooks out of the stream to save space and expects the player to supply them. This tool embeds two packed sets, retrieved by variant name via getPackedCodebooks(variant):

| variant | use for | | --- | --- | | "standard" | most Wwise titles (default) | | "aoTuV_603" | Rocksmith and newer / aoTuV-based Wwise titles |

The codebooks are embedded in the package (base64), so getPackedCodebooks() does no filesystem access and works unchanged under bundlers and Electron/asar.

Wrong codebooks still "work" but produce garbage / choppy noise — Vorbis is permissive and won't error out. If your output is noise, you're on the wrong set; switch to the other one. A reliable tell: ffmpeg prints Overread N bits while decoding when the codebooks are wrong, and decodes silently when they're right.

Some streams instead carry their codebooks inline — in that case pass inlineCodebooks: true (--inline-codebooks) and no external file is needed. If a conversion fails with invalid codebook id, that's the hint to either switch codebook files or try --inline-codebooks / --full-setup.


API reference

Everything below is exported from the package root.

convertWwiseRiffToOgg(input, options?): ConvertResult

The main entry point.

function convertWwiseRiffToOgg(
  input: Uint8Array,
  options?: ConvertOptions,
): ConvertResult;
  • input — the raw .wem (Wwise RIFF/RIFX) bytes.
  • options — see ConvertOptions. May be omitted only for streams that carry their codebooks inline.
  • returns — ConvertResult. Throws on malformed input or a missing/mismatched codebook (see Errors).

ConvertOptions

interface ConvertOptions {
  /** Packed codebook bytes. Required unless `inlineCodebooks` or `fullSetup`. */
  codebooks?: Uint8Array;

  /** The stream carries its own codebooks; no external `codebooks` needed. */
  inlineCodebooks?: boolean;

  /** Setup header is left almost intact. Implies `inlineCodebooks`. */
  fullSetup?: boolean;

  /** Override mod-packet auto-detection. See `ForcePacketFormat`. */
  forcePacketFormat?: ForcePacketFormat;

  /**
   * Recompute Ogg granule positions so duration and seeking are correct.
   * Default `true`. Set `false` to leave granules unadjusted. Only affects
   * stripped-setup streams; silently skipped for full-setup / header-triad.
   */
  recomputeGranule?: boolean;

  /** Label used in error/info messages for the input. Default `"<memory>"`. */
  sourceName?: string;

  /** Label used in error/info messages for the codebook set. */
  codebooksName?: string;
}

ConvertResult

interface ConvertResult {
  /** The generated Ogg Vorbis bitstream, as a Node Buffer. */
  ogg: Buffer;
  /** Human-readable multi-line stream summary. */
  info: string;
}

Example info output:

RIFF WAVE 2 channels 48000 Hz 128000 bps
1411200 samples
- 6 byte packet headers
- stripped setup header
- external codebooks (packed_codebooks.bin)
- modified Vorbis packets

ForcePacketFormat

Overrides the automatic "modified packets" detection. Only touch this if auto-detection guesses wrong (rare).

enum ForcePacketFormat {
  NoForce      = "no-force", // default: auto-detect
  ModPackets   = "mod",      // force modified Vorbis packets
  NoModPackets = "no-mod",   // force standard Vorbis packets
}

VERSION

const VERSION: string; // e.g. "0.24"

getPackedCodebooks(variant?): Buffer

Returns the bytes of a packed codebook library bundled with the package. The codebooks are embedded (base64), so this performs no filesystem access and works unchanged under bundlers and Electron/asar — no need to resolve or ship a .bin file yourself.

import { convertWwiseRiffToOgg, getPackedCodebooks } from "ww2ogg-ts";

getPackedCodebooks();             // bytes of the standard library
getPackedCodebooks("aoTuV_603");  // bytes of the aoTuV 6.03 library

const { ogg } = convertWwiseRiffToOgg(wem, { codebooks: getPackedCodebooks() });

variant is "standard" (default) or "aoTuV_603" (type CodebooksVariant). The buffer is decoded lazily on first use and memoized, so consumers that never need the bundled codebooks pay nothing.

CodebookLibrary

Lower-level class for working with a packed codebook set directly. Most users never need this — convertWwiseRiffToOgg handles it internally. Exported for advanced use.

Error classes

ArgumentError, FileOpenError, ParseError, SizeMismatch, InvalidId — all exported. See Errors.


CLI reference

usage: ww2ogg input.wem [-o output.ogg] [--inline-codebooks] [--full-setup]
                        [--mod-packets | --no-mod-packets]
                        [--pcb packed_codebooks.bin] [--no-revorb]

| flag | effect | | --- | --- | | -o <file> | output filename; defaults to the input with .ogg | | --pcb <file> | use a specific packed codebook file | | --inline-codebooks | the stream carries its own codebooks | | --full-setup | setup header left almost intact (implies --inline-codebooks) | | --mod-packets | force modified Vorbis packets | | --no-mod-packets | force standard Vorbis packets | | --no-revorb | skip granule recomputation (leave granules unadjusted) |

--mod-packets and --no-mod-packets are mutually exclusive. When neither --pcb nor an inline flag is given, the bundled standard codebooks are used. Exit code is 0 on success, 1 on any error (the message is printed to stdout).

Run via the package bin (npx ww2ogg-ts …) or, from a source checkout, npm run ww2ogg -- <args>.


Granule recomputation

Wwise strips granule positions from the stream. Left as-is, the resulting .ogg reports an inflated duration and seeks imprecisely (straight-through playback is fine). This tool fixes it by recomputing each page's granule from the Vorbis block sizes:

granpos += (last_blocksize + this_blocksize) / 4   // per audio packet

Because exactly one audio packet is emitted per Ogg page, the recomputation is folded into generation (reusing the mode/block-size table already recovered) rather than run as a second demux/remux pass — same result, less work.

  • On by default. Disable with --no-revorb / recomputeGranule: false.
  • Only applies to stripped-setup streams (the common case). Full-setup and header-triad streams keep their original granules; the option is silently ignored for them.

Errors

The library throws typed errors; catch and branch on them as needed. All extend the standard Error.

| class | thrown when | notes | | --- | --- | --- | | ArgumentError | bad CLI arguments | CLI only | | FileOpenError | a file couldn't be read | CLI only | | ParseError | the input isn't valid Wwise RIFF/RIFX Vorbis | base class | | SizeMismatch | a bit-size check failed while rebuilding | extends ParseError | | InvalidId | a referenced codebook id isn't in the set | extends ParseError; has .id and the message suggests --inline-codebooks |

import { convertWwiseRiffToOgg, InvalidId } from "ww2ogg-ts";

try {
  const { ogg } = convertWwiseRiffToOgg(wem, { codebooks });
} catch (err) {
  if (err instanceof InvalidId) {
    // wrong codebook set, or codebooks are inline — try the alternate .bin
    // or pass inlineCodebooks: true
  }
  throw err;
}

Browser usage

The core is filesystem-free, so it runs in the browser once bundled. Feed it a Uint8Array (e.g. from fetch or a file input) and ship the codebook bytes as an asset:

import { convertWwiseRiffToOgg } from "ww2ogg-ts";

const [wem, codebooks] = await Promise.all([
  fetch("/song.wem").then((r) => r.arrayBuffer()).then((b) => new Uint8Array(b)),
  fetch("/packed_codebooks.bin").then((r) => r.arrayBuffer()).then((b) => new Uint8Array(b)),
]);

const { ogg } = convertWwiseRiffToOgg(wem, { codebooks });
const url = URL.createObjectURL(new Blob([ogg], { type: "audio/ogg" }));

Note: ConvertResult.ogg is typed as a Node Buffer, which is a Uint8Array subclass — Blob, URL.createObjectURL, and friends accept it directly. A Buffer polyfill is only needed if your bundler doesn't provide one.


Building from source

git clone <repo-url> ww2ogg-ts
cd ww2ogg-ts
npm install
npm run build      # tsc -> dist/
npm run smoke      # self-checks: codebook parsing, bit round-trip, CRC

| script | what it does | | --- | --- | | npm run build | compile src/ to dist/ | | npm run clean | remove dist/ | | npm run smoke | run the built-in self-checks | | npm run ww2ogg -- <args> | run the CLI from source |


How it works

The pipeline, module by module:

| module | responsibility | | --- | --- | | src/wwriff.ts | parse Wwise RIFF/RIFX, rebuild Vorbis headers, emit Ogg | | src/codebook.ts | packed Vorbis codebook library (external + inline) | | src/bit-stream.ts, src/binary.ts | LSB-first bit readers and integer helpers | | src/bit-oggstream.ts | pack bits into Ogg pages and write the container | | src/crc.ts | Ogg page CRC-32 | | src/errors.ts | typed error hierarchy | | src/index.ts | public entry point (convertWwiseRiffToOgg) | | src/cli.ts | command-line front end |

In short: read the RIFF/RIFX chunks → recover the Vorbis identification, comment, and setup headers (pulling codebooks from the packed set or inline) → repackage the audio packets into standard Ogg pages, recomputing granule positions along the way.


Credits

This library is a TypeScript port of ww2ogg by Adam Gashlin (hcs). The conversion algorithm and the packed codebook data files come from that project; the Vorbis codebook / CRC helpers derive from Tremor (Xiph.Org).

License

BSD-3-Clause. See LICENSE.