Skip to content

Low-level API ​

createEspeak covers the usual cases. The pieces it is built from are exported too, for setups where the module or the data come from somewhere else: a custom cache, data bundled into an app, a module instantiated by your own loader, or tests.

ts
import {
  Espeak,
  DataLoader,
  DATA_PATH,
} from "@spelling-creator/spellophone/core";
import createEspeakModule from "@spelling-creator/spellophone/wasm/espeak-ng.js";

@spelling-creator/spellophone/core is the runtime-neutral part: no Node.js imports, no fetch. It is what @spelling-creator/spellophone/node and @spelling-creator/spellophone/browser re-export.

Putting it together ​

ts
import createEspeakModule from "@spelling-creator/spellophone/wasm/espeak-ng.js";
import {
  DataLoader,
  Espeak,
  httpDataSource,
  moduleFactoryOptions,
} from "@spelling-creator/spellophone/core";

// 1. Instantiate the wasm module.
const module = await createEspeakModule(moduleFactoryOptions());

// 2. Get a data source and copy the data into the module's file system.
const source = await httpDataSource("/espeak-ng-data/");
const loader = new DataLoader(module, source);
await loader.loadCore();
await loader.loadDictionary("en"); // espeak-ng needs English to initialize

// 3. Initialize espeak-ng.
const espeak = Espeak.create(module, { loader });

DataSource ​

Where the data files come from:

ts
interface DataSource {
  manifest: DataManifest; // the parsed manifest.json
  read(file: string): Promise<Uint8Array>; // decoded bytes of a file named in it
  readSync?(file: string): Uint8Array; // optional; enables loading on demand
}

read returns decoded (decompressed) bytes. When readSync is present, Espeak.setVoice loads a missing dictionary on the spot; without it, callers use loadVoice or loadLanguages first.

Two implementations ship with the package:

  • httpDataSource(baseUrl, fetch?, decode?) fetches from a URL (browsers). decode replaces the decompression step, for engines without DecompressionStream. A .gz file that arrives without the gzip magic bytes, because the server sent it with Content-Encoding: gzip and the browser already unzipped it, skips that step.
  • fileDataSource(dir?) reads from a directory (@spelling-creator/spellophone/node only).

decode(bytes, encoding) is the decompression helper httpDataSource uses by default.

DataLoader ​

Copies files from a DataSource into the module's virtual file system at dataPath (default /espeak-ng-data):

MethodDescription
loadCore()Writes everything except the dictionaries
loadDictionary(language)Fetches and writes one dictionary
loadDictionarySync(language)Same, via readSync; returns false if absent
hasDictionary(language)Whether a dictionary is in the file system
availableLanguages()Languages in the manifest
loadedLanguages()Languages whose dictionary is loaded

Espeak.create(module, options?) ​

Initializes espeak-ng on an instantiated module whose file system already holds the core data and the English dictionary.

ts
interface EspeakOptions {
  dataPath?: string; // default "/espeak-ng-data"
  phonemeEvents?: boolean | "ipa";
  loader?: DataLoader; // enables loadVoice and loadLanguages
}

moduleFactoryOptions(wasmUrl?) ​

The options the entry points pass to the module factory: an optional locateFile for the wasm, and a printErr that drops espeak-ng's "Can't read dictionary file" message (an expected event, since it is what triggers loading the dictionary) while letting everything else through to console.error.

The wasm2js module ​

@spelling-creator/spellophone/wasm2js exports createWasm2jsModule(options?), which returns the same module without WebAssembly: espeak-ng compiled to JavaScript by Binaryen's wasm2js. It takes the same options as the wasm factory (only printErr matters) and works with DataLoader and Espeak.create the same way:

ts
import { createWasm2jsModule } from "@spelling-creator/spellophone/wasm2js";

const module = await createWasm2jsModule(moduleFactoryOptions());

It is what the browser entry point's fallback loads, and what the legacy build is built on. Behind it are two generated files in the package's wasm/ directory: espeak-ng.legacy.js, the Emscripten glue, and espeak-ng.legacy.wasm.js, the module itself.

The wasm module ​

@spelling-creator/spellophone/wasm/espeak-ng.js is the Emscripten-generated ES module. Its default export is the module factory; the MainModule type lists the _sp_* functions the C glue exports. They take and return integers and C strings and are documented in packages/spellophone/native/glue.c. Espeak.module gives access to them on a running instance, should you need something the wrapper does not expose.

EspeakModule, the type the rest of the API takes, is MainModule minus NODEFS, so the wasm2js module fits it too.

Released under the GPL-3.0-or-later license.