> ## Documentation Index
> Fetch the complete documentation index at: https://docs.runanywhere.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# TTS Output

> Working with synthesized audio output

<Note>**Early Beta** -- The Web SDK is in early beta. APIs may change between releases.</Note>

## Overview

The Web SDK's TTS produces raw PCM audio as `Float32Array`. This page covers how to work with the audio output, including playback, conversion, and integration with Web Audio API.

<Note>
  The Web SDK currently produces audio all-at-once (non-streaming). Streaming TTS output is planned
  for a future release.
</Note>

## Playing Audio

### Using AudioPlayback

The SDK includes a built-in `AudioPlayback` class for playing synthesized audio:

```typescript theme={null}
import { TTS, AudioPlayback } from '@runanywhere/web'

const result = await TTS.synthesize('Hello from RunAnywhere!')

const player = new AudioPlayback()
player.onComplete(() => console.log('Playback finished'))
await player.play(result.audioData, result.sampleRate)
```

### Stop Playback

```typescript theme={null}
const player = new AudioPlayback()
await player.play(audioData, sampleRate)

// Stop playback at any time
player.stop()
```

### Using Web Audio API Directly

For more control, use the Web Audio API directly:

```typescript theme={null}
import { TTS } from '@runanywhere/web'

const result = await TTS.synthesize('Hello world')

const audioCtx = new AudioContext()
const buffer = audioCtx.createBuffer(1, result.audioData.length, result.sampleRate)
buffer.getChannelData(0).set(result.audioData)

const source = audioCtx.createBufferSource()
source.buffer = buffer
source.connect(audioCtx.destination)
source.start()
```

## Converting to WAV

Convert synthesized audio to WAV format for download or storage:

```typescript theme={null}
function float32ToWav(samples: Float32Array, sampleRate: number): Blob {
  const buffer = new ArrayBuffer(44 + samples.length * 2)
  const view = new DataView(buffer)

  // WAV header
  const writeString = (offset: number, str: string) => {
    for (let i = 0; i < str.length; i++) {
      view.setUint8(offset + i, str.charCodeAt(i))
    }
  }

  writeString(0, 'RIFF')
  view.setUint32(4, 36 + samples.length * 2, true)
  writeString(8, 'WAVE')
  writeString(12, 'fmt ')
  view.setUint32(16, 16, true)
  view.setUint16(20, 1, true) // PCM
  view.setUint16(22, 1, true) // mono
  view.setUint32(24, sampleRate, true)
  view.setUint32(28, sampleRate * 2, true)
  view.setUint16(32, 2, true)
  view.setUint16(34, 16, true)
  writeString(36, 'data')
  view.setUint32(40, samples.length * 2, true)

  // Convert float32 to int16
  for (let i = 0; i < samples.length; i++) {
    const s = Math.max(-1, Math.min(1, samples[i]))
    view.setInt16(44 + i * 2, s < 0 ? s * 0x8000 : s * 0x7fff, true)
  }

  return new Blob([buffer], { type: 'audio/wav' })
}

// Usage
const result = await TTS.synthesize('Hello world')
const wavBlob = float32ToWav(result.audioData, result.sampleRate)

// Download
const url = URL.createObjectURL(wavBlob)
const a = document.createElement('a')
a.href = url
a.download = 'speech.wav'
a.click()
URL.revokeObjectURL(url)
```

## Queuing Multiple Utterances

Play multiple TTS results in sequence:

```typescript theme={null}
async function speakSequence(texts: string[]) {
  const player = new AudioPlayback()

  for (const text of texts) {
    const result = await TTS.synthesize(text)
    await player.play(result.audioData, result.sampleRate)
  }
}

await speakSequence(['First sentence.', 'Second sentence.', 'And the third.'])
```

## Related

<CardGroup cols={2}>
  <Card title="Synthesize" icon="volume-high" href="/web/tts/synthesize">
    Text-to-Speech synthesis
  </Card>

  <Card title="TTS Voices" icon="waveform" href="/web/tts/voices">
    Voice management
  </Card>
</CardGroup>
