Skip to content

feat(media-use): your own voice recording is a voice line, and speed applies to it - #7377

Merged
miguel-heygen merged 2 commits into
mainfrom
feat/voice-own-recording
Nov 7, 2026
Merged

miguel-heygen merged 2 commits into
mainfrom
feat/voice-own-recording

Conversation

@miguel-heygen

Copy link
Copy Markdown
Collaborator

What

The voice step takes your own recording as a line: { "id": "01", "audio": "take.m4a", "words": [{ "text", "start", "end" }] } in audio_request.json. The file is converted to the engine's wav, speed time-stretches it with the pitch kept, and the given word timings are scaled the same, so the words still land on the audio. Without words, the recording is transcribed (the existing path). The voice in audio_meta.json carries source: "recording", and a run of only recording lines needs no TTS provider and no HeyGen sign-in.

Why

Discord, "Use your own voice recording": the voice step only worked with HeyGen voices; with your own recording the speed setting was ignored. Root cause: audio.mjs only accepted text lines and sent speed to the TTS provider alone (synthesizeHeygen body.speed, Kokoro --speed), so there was no path where a recording could be stretched or its timings scaled.

Related work

Refs the same Discord report as #7366 (merged: transcribe error). The credits line that names the real voice source is the next PR.

How

New skills/media-use/audio/scripts/lib/recording.mjs (ffmpeg atempo chain for 0.1 to 3x, word parsing, word scaling). audio.mjs routes a line with audio through it and only picks a TTS provider when some line has text. media-record.mjs includes recording lines in the voice paths and the media manifest. lib/tts.mjs is untouched. Searched for an existing stretch helper in skills: none (grep -rn atempo skills); the engine's buildAtempoFilter is TypeScript inside the render package, not reachable from these standalone scripts.

Test plan

  • fails without the fix: skills/media-use/audio/scripts/recording.test.mjs "scaleWords moves words by 1/speed" and "a recording at speed 2: the file is stretched and the words still land on the audio" (both fail with the word scaling removed).
  • The speed-2 test builds a 1 s gap plus a 1 s tone, runs audio.mjs for real, and checks with ffmpeg silencedetect that the tone starts where the scaled word says (within 80 ms), and the file is 1 s long.
  • Malformed words omit that line with the reason instead of crashing.
  • node --test on recording, media-record and audio tests on a remote box: 26 passed, 0 skipped; oxfmt --check and oxlint clean on the four files.
  • Not run: a real spoken recording through the transcribe path (no speech fixture in the repo).
  • Documentation updated (skills/media-use/references/audio.md)
  • Comments follow CONTRIBUTING.md

@heygengenesis heygengenesis Bot 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.

Verdict: REQUEST CHANGES · 2 blocker · 0 important · 1 nit · head 98237123

  • blocker CI "Skills: manifest in sync" fails: skills-manifest.json is out of date — a skill changed without regenerating it. Run bun run --cwd packages/cli gen:skills-manifest and commit the result.
  • blocker The Comments check fails: the header block at audio.mjs:2 grew to 41 lines, over the 40-line limit, because of the new example-line comment. Cut a line, or move the recording example into references/audio.md, which already documents it.
  • nit media-record.mjs:62: a recording line is still written to the manifest as source: "generated". You note the credits line comes next; worth fixing there too.
Scope

Read audio.mjs, recording.mjs and the media-record.mjs diff. The atempo chain, word scaling and the provider skip for recording-only runs look right. The "fails without the fix" line names two tests. I didn't run them locally; the verdict rests on the CI failures.

@miguel-heygen

Copy link
Copy Markdown
Collaborator Author

Pushed aa8e47e.

  • Skills manifest: regenerated with gen:skills-manifest.
  • Comments check: removed the recording example from the audio.mjs header, so the header block is back to its size on main; the example lives in skills/media-use/references/audio.md.
  • Manifest source: a recording's converted copy stays an agent source on purpose (AGENT_SOURCES, skills/media-use/scripts/lib/manifest.mjs:84): anything else makes every rerun write a numbered copy beside it. What marks it as the person's own voice is its provenance (provider: "recording", intent "your own recording"); a new test in media-record.test.mjs pins that.

@heygengenesis heygengenesis Bot 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.

Verdict: APPROVE — 3 resolved, 0 open, 0 new · 98237123 → aa8e47e0. The manifest is regenerated, the header is back to 38 lines with the example in references/audio.md, and keeping source as an agent source is justified and pinned by the new media-record test. CI is green.

@miguel-heygen
miguel-heygen added this pull request to the merge queue Nov 7, 2026
Merged via the queue into main with commit 14e598e Nov 7, 2026
62 checks passed
@miguel-heygen
miguel-heygen deleted the feat/voice-own-recording branch November 7, 2026 20:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant