Skip to content
Sign in
AudioTTS studioMenu

TTS studioPro

A long form script editor for speech: a voice per paragraph, expressive tags inside the text, stale marks after edits, regenerate one sentence at the caret, and a timeline of takes with play all and take switching.

ProA four paragraph script in three voices. Edit a paragraph and it says it is stale, put the caret in a sentence to redo just that one, or play the whole timeline.

Installation

$ pnpm dlx shadcn@latest add @chatcn-pro/tts-studio

Usage

tsx
import { TtsStudio } from "@/components/ui/chatcn/pro/tts-studio"

<TtsStudio
  voices={voices}
  paragraphs={paragraphs}
  onParagraphsChange={setParagraphs}
  onGenerate={({ paragraphId, text, voiceId, sentence }) => synthesize(paragraphId, text, voiceId, sentence)}
  onExport={exportMix}
/>

A paragraph is { id, voiceId, text, takes, activeTake, status, generatedText }. Set status: "generating" when a request starts and append the take when it lands, with generatedText set to the text it was made from: when the text changes after that, the paragraph says it is out of date and Generate all picks it up. A take with sentence set redid that sentence only.

The examples play a demo synthesizer built on the Web Audio API (renderBabble and renderSfx in @/lib/chatcn-pro-speech): it sounds like a voice behind a wall, so nothing pretends to be a real model. Pass your API's audio as URLs or buffers instead.

Examples

States

ProEdited since its take, one sentence regenerating, a failed paragraph and a new script.

Props

PropTypeNotes
paragraphs, defaultParagraphs, onParagraphsChangeStudioParagraph[]
voicesSpeechVoice[]Required. Each paragraph picks one with the free voice-picker
onGenerate(request) => voidParagraph id, text, voice, and sentence for one sentence
onExport() => voidEnabled once every paragraph has a current take
titleReactNodeDefault Script
tagsAudioTagInfo[]The tags your model reads, for the autocomplete
labelsPartial<TtsStudioLabels>Every string the studio shows or announces, for translation
disabled, locale

Keyboard

KeyAction
Alt + EnterRegenerate the sentence at the caret
⌘ or Ctrl + EnterRegenerate the paragraph
[Open the tag menu inside the text
TabVoice, text, play, regenerate, then the timeline clips and takes

Accessibility

  • Each paragraph's text is named with its number and voice and described by its status: not generated, out of date, generating, or which take plays.
  • Timeline clips are buttons that say the paragraph, the voice, the length and whether it is stale.
  • Status has a word as well as a color; the stale mark is amber with its sentence.

Motion

  • Typing never animates. A generating paragraph shows the text shimmer after 300 ms, and its clip keeps its width, so nothing reflows.
  • A new take fades into its clip over 200 ms; the playhead moves with the audio.