# signalsmith-stretch-js

Strict TypeScript bindings for the MIT-licensed Signalsmith Stretch C++ pitch/time library, compiled to WebAssembly. It processes planar PCM locally in modern browsers without exposing pointers or Emscripten memory.

## Install

```sh
npm install signalsmith-stretch-js
```

The package includes its own TypeScript declarations and precompiled `.wasm`. Consumers do not need Emscripten, C++, or a separate `@types` package.

## Live Web Audio

The default export creates an `AudioWorkletNode` which can be connected directly into a live Web Audio graph:

```ts
import SignalsmithStretch from "signalsmith-stretch-js";

const stretch = await SignalsmithStretch(audioContext, {
  numberOfInputs: 1,
  numberOfOutputs: 1,
  outputChannelCount: [2]
});

source.connect(stretch);
stretch.connect(dry);
stretch.connect(reverb);

await stretch.start({ active: true, semitones: 0 });
await stretch.schedule({
  output: audioContext.currentTime + 0.05,
  semitones: 7
});
```

The node also provides the upstream-compatible `start()`, `stop()`, `schedule()`, `configure()`, `latency()`, `addBuffers()`, `dropBuffers()`, and `setUpdateInterval()` methods. For live input, `rate`, `input`, and loop controls are ignored; pitch and formant controls remain live. The same factory is available from `signalsmith-stretch-js/worklet`.

## PCM processing

```ts
import { createSignalsmithStretch } from "signalsmith-stretch-js";

const stretch = await createSignalsmithStretch();
const result = await stretch.process({
  sampleRate: 44_100,
  channels: [left, right],
  timeRatio: 1.2,       // 20% longer/slower
  pitchSemitones: -2,
  quality: "high",
  advanced: {
    formantCompensation: true,
    formantBaseHz: 180
  }
});
stretch.dispose();
```

`timeRatio` is output duration divided by input duration. `pitchScale: 1` is unchanged, `2` is one octave up, and `0.5` is one octave down. Do not provide `pitchScale` and `pitchSemitones` together.

## AudioBuffer helper

```ts
import { processAudioBuffer } from "signalsmith-stretch-js/browser";

const output = await processAudioBuffer(audioContext, inputBuffer, {
  timeRatio: 1.15,
  pitchSemitones: -2,
  quality: "high"
});
```

The browser entry point also exports `audioBufferToAudioData` and `audioDataToAudioBuffer`.

## Web Worker

```ts
import { SignalsmithStretchWorkerClient } from "signalsmith-stretch-js/worker";

const worker = await SignalsmithStretchWorkerClient.create();
const result = await worker.process({ sampleRate: 48_000, channels, timeRatio: 0.9 });
worker.dispose();
```

Worker inputs are copied before transfer, so caller-owned arrays are not detached.

## Streaming

```ts
const engine = await createSignalsmithStretch();
const stream = await engine.createStreamProcessor({
  sampleRate: 48_000,
  channels: 2,
  timeRatio: 1.1,
  maxBlockSize: 4096
});

const output = stream.process([leftBlock, rightBlock]);
const tail = stream.flush();
stream.dispose();
engine.dispose();
```

The stream API reports algorithm latency and returns the remaining tail from `flush()`. It is block streaming, not an AudioWorklet or a hard-realtime guarantee.

## Quality and formants

| Preset | Signalsmith configuration |
| --- | --- |
| `fast` | `presetCheaper` |
| `balanced` | `presetDefault` |
| `high` | `presetDefault` (reserved for future higher-quality tuning) |

The `advanced` object supports `tonalityLimitHz`, `formantScale` or `formantSemitones`, `formantCompensation`, and `formantBaseHz`.

Signalsmith says time-stretching sounds best for moderate changes around `0.75x–1.5x`. More extreme ratios are supported but can produce stronger artifacts.

## WASM loading

The package resolves `signalsmith-stretch-wasm.wasm` relative to its emitted ES module. A CDN or custom deployment can override it:

```ts
await createSignalsmithStretch({
  wasmUrl: new URL("https://cdn.example.com/signalsmith-stretch-wasm.wasm")
});
```

Serve `.wasm` as `application/wasm`. This build is single-threaded and does not require cross-origin isolation.

## Scope

This package transforms decoded PCM. It does not decode MP3/AAC, encode files, play audio, render UI, upload files, or provide a backend. Use Web Audio for decoding/playback and a separate encoder for export.

## Licence

The wrapper and bundled Signalsmith sources are MIT-licensed, so they can be used in closed-source and commercial applications while retaining the required copyright and licence notices. See [THIRD_PARTY_LICENSES.md](./THIRD_PARTY_LICENSES.md).

## Development

Pinned inputs:

- Signalsmith Stretch 1.3.2, commit `57b93f4e9206a089a45387eaa39bdc9f310d3308`
- Signalsmith Linear 0.3.1, commit `5668673560146a9cfe38c25315071e3fd68c8317`
- Emscripten 6.0.2

```sh
npm install
npm run build
npm test
npm run pack:check
```

Consumers receive prebuilt WASM and need no native toolchain.
