Skip to content

[RNE Rewrite] feat: add supertonic TTS pipeline - #1317

Merged
barhanc merged 21 commits into
rne-rewritefrom
@bh/tts
Aug 7, 2026
Merged

[RNE Rewrite] feat: add supertonic TTS pipeline#1317
barhanc merged 21 commits into
rne-rewritefrom
@bh/tts

Conversation

@barhanc

@barhanc barhanc commented Jul 17, 2026

Copy link
Copy Markdown
Member

Description

Add supertonic TTS pipeline and example app screen to test it.

Introduces a breaking change?

  • Yes
  • No

Type of change

  • Bug fix (change which fixes an issue)
  • New feature (change which adds functionality)
  • Documentation update (improves or adds clarity to existing documentation)
  • Other (chores, tests, code style improvements etc.)

Tested on

  • iOS
  • Android

Testing instructions

  • Run the Speech example app on both iOS and Android and test the newly added TTS functionality.

Screenshots

Related issues

Part of #1250

Checklist

  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • I have updated the documentation accordingly
  • My changes generate no new warnings

Additional notes

Should wait for #1328 so that the hook implementation can be refactored to a more concise and elegant one.

@barhanc barhanc self-assigned this Jul 17, 2026
@barhanc barhanc added refactoring feature PRs that implement a new feature labels Jul 17, 2026
@barhanc barhanc changed the title feat: add supertonic helpers [RNE Rewrite] feat: add supertonic TTS pipeline Jul 17, 2026
@barhanc
barhanc marked this pull request as ready for review August 5, 2026 16:53
@barhanc
barhanc requested review from IgorSwat and msluszniak August 5, 2026 16:58
*/
synthesize: (
text: string,
options: SupertonicTtsOptions<K>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is our convention right now, when do we use opts and when options?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In all task pipeline implementations we use options right now for user-facing API. In helpers we mostly use opts but there are some inconsistencies there. I think we should make them all use one or the other (which one would you prefer?), but this can be done in a follow-up style PR.

@msluszniak msluszniak Aug 6, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm in favour of options everywhere. Opts suffixes in config object field and types are fine I guess. Also when we add PR with refactor we should add note in core-guidelines/SKILL.md.

@msluszniak msluszniak left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Main thing is partition(), I found three cases where it misbehaves (comments inline). The first one fires on pretty much any input that doesn't end in punctuation, so I'd want that sorted before merge.

Comment thread packages/react-native-executorch/src/hooks/useTextToSpeech.ts Outdated
Comment thread packages/react-native-executorch/src/hooks/useTextToSpeech.ts Outdated
Comment thread apps/speech/app/text-to-speech/index.tsx
@msluszniak

msluszniak commented Aug 6, 2026

Copy link
Copy Markdown
Member

When I set the slowest speed aka 0.7 I got in half of the cases strange artefacts with repetitions of some parts of sentences. Exact parameters for reproduction:
device: Android
backend: Xnnpack
voice: M1
language: pl
speed: 0.7
denoising steps: 8

Sentence: "Cześć co tam słychać? Testuję funkcje mowy w naszej demo aplikacji."

EDIT: When I tested the same configuration but with speed 2.0, the results were even worse :((

@barhanc

barhanc commented Aug 6, 2026

Copy link
Copy Markdown
Member Author

When I set the slowest speed aka 0.7 I got in half of the cases strange artefacts with repetitions of some parts of sentences. Exact parameters for reproduction: device: Android backend: Xnnpack voice: M1 language: pl speed: 0.7 denoising steps: 8

Sentence: "Cześć co tam słychać? Testuję funkcje mowy w naszej demo aplikacji."

EDIT: When I tested the same configuration but with speed 2.0, the results were even worse :((

Yeah, from my experiments the extreme values for speed are often hit-or-miss depending on the voice and text to synthesize. I checked the Transformers.js implementation of Supertonic (https://huggingface.co/spaces/webml-community/Supertonic-TTS-WebGPU) and they only allow speeds in [0.8; 1.2]. This is a limitation of the model I believe so we can narrow the available speed range.

@msluszniak

Copy link
Copy Markdown
Member

Yeah, I'm in favour of limiting speed min and max.

@msluszniak msluszniak left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! If this PR is fine for you @IgorSwat ,we just need to rebase it with resource fetcher PR and ship :))

@IgorSwat IgorSwat left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Text partitioner in this form is unacceptable. It's not prioritizing low latency (time to first audio chunk) as the old one does. And it will hurt the performance (particularly for Kokoro) very seriously.

I would just add a mechanic (like a flag or smth) that if set, makes the algorithm prioritize splitting heavily at the beginning and slowly disable it as we process more and more of text.

@msluszniak

Copy link
Copy Markdown
Member

For Kokoro, there will be a separate flow I guess, since these models are too specific to support them both under same functionality.

@IgorSwat

IgorSwat commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

For Kokoro, there will be a separate flow I guess, since these models are too specific to support them both under same functionality.

In current codebase same TextPartitioner is used for both. And works fine.

@barhanc

barhanc commented Aug 6, 2026

Copy link
Copy Markdown
Member Author

Text partitioner in this form is unacceptable. It's not prioritizing low latency (time to first audio chunk) as the old one does. And it will hurt the performance (particularly for Kokoro) very seriously.

I would just add a mechanic (like a flag or smth) that if set, makes the algorithm prioritize splitting heavily at the beginning and slowly disable it as we process more and more of text.

I've added the configurable mechanism to prioritize splitting at the beginning and also made other options of the partitioner configurable.

@barhanc
barhanc requested a review from IgorSwat August 6, 2026 16:27
@msluszniak

Copy link
Copy Markdown
Member

@barhanc Would we share partitioner part across supertonic and kokoro?

@barhanc

barhanc commented Aug 6, 2026

Copy link
Copy Markdown
Member Author

Yes, right now it is very similar to the main branch one, and configurable options make it adjustable for different models.

@msluszniak

Copy link
Copy Markdown
Member

Thank you @IgorSwat for this on point observation. Please check if now everything is fine. Btw, maybe you want to add Kokoro to the new flow as a flow-up? ;)

@IgorSwat

IgorSwat commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Thank you @IgorSwat for this on point observation. Please check if now everything is fine. Btw, maybe you want to add Kokoro to the new flow as a flow-up? ;)

I will adjust my Kokoro PR after this one is merged.

@barhanc
barhanc merged commit 94521d9 into rne-rewrite Aug 7, 2026
0 of 2 checks passed
@barhanc
barhanc deleted the @bh/tts branch August 7, 2026 11:18
msluszniak added a commit that referenced this pull request Aug 10, 2026
Rebasing onto the supertonic TTS pipeline (#1317) surfaced two gaps the suites
themselves reported:

- The registry walk assumed every task config names a single `modelPath`.
  Supertonic assembles four `.pte` files under `modelPaths`, so its category
  looked empty and its variant group went unchecked. Recognize both shapes, and
  compare variants on the whole set of files they name.
- The export snapshots record the new TTS surface. Additions only — no removal
  or rename.
msluszniak added a commit that referenced this pull request Aug 10, 2026
Addresses the review threads on #1354.

Codes are no longer generated (barhanc): `scripts/errors.config.ts` and
`generate-errors.ts` are deleted along with the codegen script and CI
drift check. `src/core/error.ts` is now the source of truth and
`cpp/core/error.h` mirrors it by hand, like every other part of the
TS/JSI interface.

TypeScript:
- Codes are a string union, not a numeric enum, and the set shrinks from
  13 to 10. A code now has to justify a distinct recovery path; the
  tokenizer and not-supported codes folded into the general categories.
- One `RnExecuTorchError(code, message)` factory replaces the
  class/worklet-helper pair. It is a function, so it works unchanged on
  both runtimes rather than needing two spellings.
- `isRnExecuTorchError(err, code?)` takes an optional code to narrow.
- The internal fetcher `AbortError` class becomes a DOWNLOAD_ABORTED
  error; `useResourceDownload` matches the code instead of the class.

C++:
- `CodedError` -> `RnExecuTorchException`, `ErrorCode` ->
  `RnExecuTorchErrorCode`, `etCode` -> `etRuntimeErrorCode`.
- `throwJs` and `makeJsError` are replaced by a single
  `throwJsiRnExecuTorchError(rt, e)` that only takes the C++ exception,
  so there is no way to reach JS without constructing one first.
- `unwrapEt` leaves the error namespace and goes back to being a
  file-local `unwrap` helper with a single signature, no jsi::Runtime.

Example apps are reverted to their original state: they are a testing
ground and should surface raw errors (barhanc, #1288). The new Supertonic
TTS throw sites from #1317 are converted to the convention.

Agent skills are updated to match.
barhanc added a commit that referenced this pull request Aug 10, 2026
## Description

Changes naming from `opts` to `options` across the board in TS API.
Follow-up to
[comment](https://github.com/software-mansion/react-native-executorch/pull/1317#:~:text=I%27m%20in%20favour%20of%20options%20everywhere.%20Opts%20suffixes%20in%20config%20object%20field%20and%20types%20are%20fine%20I%20guess.%20Also%20when%20we%20add%20PR%20with%20refactor%20we%20should%20add%20note%20in%20core%2Dguidelines/SKILL.md.)
from #1317

### Introduces a breaking change?

- [ ] Yes
- [x] No

### Type of change

- [ ] Bug fix (change which fixes an issue)
- [ ] New feature (change which adds functionality)
- [ ] Documentation update (improves or adds clarity to existing
documentation)
- [x] Other (chores, tests, code style improvements etc.)

### Tested on

- [ ] iOS
- [ ] Android

### Testing instructions

N/A

### Screenshots

<!-- Add screenshots here, if applicable -->

### Related issues

<!-- Link related issues here using #issue-number -->

### Checklist

- [ ] I have performed a self-review of my code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have updated the documentation accordingly
- [ ] My changes generate no new warnings

### Additional notes

<!-- Include any additional information, assumptions, or context that
reviewers might need to understand this PR. -->
msluszniak added a commit that referenced this pull request Aug 11, 2026
Addresses the review threads on #1354.

Codes are no longer generated (barhanc): `scripts/errors.config.ts` and
`generate-errors.ts` are deleted along with the codegen script and CI
drift check. `src/core/error.ts` is now the source of truth and
`cpp/core/error.h` mirrors it by hand, like every other part of the
TS/JSI interface.

TypeScript:
- Codes are a string union, not a numeric enum, and the set shrinks from
  13 to 10. A code now has to justify a distinct recovery path; the
  tokenizer and not-supported codes folded into the general categories.
- One `RnExecuTorchError(code, message)` factory replaces the
  class/worklet-helper pair. It is a function, so it works unchanged on
  both runtimes rather than needing two spellings.
- `isRnExecuTorchError(err, code?)` takes an optional code to narrow.
- The internal fetcher `AbortError` class becomes a DOWNLOAD_ABORTED
  error; `useResourceDownload` matches the code instead of the class.

C++:
- `CodedError` -> `RnExecuTorchException`, `ErrorCode` ->
  `RnExecuTorchErrorCode`, `etCode` -> `etRuntimeErrorCode`.
- `throwJs` and `makeJsError` are replaced by a single
  `throwJsiRnExecuTorchError(rt, e)` that only takes the C++ exception,
  so there is no way to reach JS without constructing one first.
- `unwrapEt` leaves the error namespace and goes back to being a
  file-local `unwrap` helper with a single signature, no jsi::Runtime.

Example apps are reverted to their original state: they are a testing
ground and should surface raw errors (barhanc, #1288). The new Supertonic
TTS throw sites from #1317 are converted to the convention.

Agent skills are updated to match.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature PRs that implement a new feature refactoring

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[RNE Rewrite] Speech - add Kokoro/Supertonic TTS pipeline implementation

3 participants