Nodaro ドキュメント
ドキュメントノードリファレンスモデルAI エージェント(MCP)開発者向けセルフホスティングリサーチ
TypeScript SDK

ボイスとオーディオ

Nodaro SDK を使って、TypeScript からボイスの参照、変更、差し替え、デザイン、動画の吹き替え、オーディオの分離、ミックス、文字起こしを行います。

client.voices は ElevenLabs のボイスを扱います。ボイスの一覧表示と検索、録音の声の変更、話者ごとの新しいボイスの割り当て、新しいボイスのデザイン、オーディオや動画の別の言語への吹き替えができます。client.audio は、オーディオの構成要素をそれぞれ単独で提供します。分離、声の抽出、エフェクト、ミックス、音量、結合、文字起こしです。どの生成メソッドも jobId を返すので、client.jobs.getStatus() でポーリングしてください。これらのメソッドは、音声とメディアの REST API を呼び出します。

メソッド

メソッド内容
voices.list()標準ボイスを一覧表示します
voices.searchLibrary(params?)コミュニティのボイスライブラリを検索します
voices.listClones()既存のボイスクローンを一覧表示します
voices.deleteClone(id)ボイスクローンの 1 つを削除します
voices.createClone() と createCloneFromFile()廃止されました
voices.change(input)録音や動画の声を差し替えます
voices.recast(input)話者ごとに異なるボイスを割り当てます
voices.analyze(input)差し替えの前に話者を検出します
voices.exportMix(input)ミックスしたボイスのステムから動画をレンダリングします
voices.design(input)説明から新しいボイスを作成します
voices.remix(input)説明したボイスでテキストを話します
voices.dub(input)オーディオや動画を別の言語に吹き替えます
voices.textToDialogue(input)複数話者の脚本を 1 つのオーディオファイルとして音声にします
audio.separate(input)トラックをステムに分割します
audio.isolate(input)主な声を残し、ノイズを取り除きます
audio.applyFx(input)リバーブ、エコー、電話、メガホンを加えます
audio.mix(input)複数のトラックを重ねて 1 つにします
audio.adjustVolume(input)レベルの変更、ノーマライズ、フェードを行います
audio.combine(input)オーディオのセグメントを順番につなげます
audio.transcribe(input)単語のタイミング付きで、音声をテキストにします

client.voices:ボイス

voices.list()

ElevenLabs の標準ボイスを一覧表示します(GET /v1/voices)。サーバーに ElevenLabs のキーが設定されていない場合は、代わりに厳選されたセットを返します。

list(): Promise<Voice[]>
const voices = await client.voices.list()

voices.searchLibrary(params?)

コミュニティのボイスライブラリを検索します(GET /v1/voices/library)。どのパラメーターも任意で、空の値は取り除かれるため、サーバーのデフォルトが適用されます。応答の hasMore で、次のページがあるかどうかがわかります。

searchLibrary(params?: VoiceLibraryParams): Promise<{ voices: Voice[]; hasMore: boolean }>

Prop

Type

const { voices, hasMore } = await client.voices.searchLibrary({ search: "deep", language: "en" })
const voice = voices[0]

await client.nodes.run("text-to-speech", {
  text: "Hello!",
  voice: voice.voice_id,
  voiceType: "library",
  ...(voice.recommendedProvider ? { provider: voice.recommendedProvider } : {}),
})

各ボイスには、そのボイスが検証済みの音声モデルについて、2 つのヒントが付くことがあります。

  • recommendedProvider は、そのボイスに最適なモデルです。モデルピッカーのないアプリは、これを provider としてテキストから音声(Text to Speech)に送ってください。そうすると、ボイスがライブラリのプレビューと同じように聞こえます。
  • verifiedProviders は、そのボイスが検証済みのすべてのモデルを一覧にします。モデルピッカーのあるアプリは、ユーザーの選んだモデルがこの一覧にない場合にだけ、それを置き換えてください。

voices.listClones()

自分のボイスクローンを一覧表示します(GET /v1/voice-clones)。クローン機能が廃止される前に作ったクローンは、ボイスを指定できるところならどこでも、ボイス ID として引き続き使えます。

listClones(): Promise<VoiceClone[]>
const clones = await client.voices.listClones()

voices.deleteClone(id)

自分のボイスクローンの 1 つを削除します(DELETE /v1/voice-clones/:id)。

deleteClone(id: string): Promise<void>

Prop

Type

await client.voices.deleteClone(cloneId)

voices.createClone() と createCloneFromFile()

ボイスクローンの作成は、Nodaro ではもう提供されていません。2026 年 9 月に廃止されました。両方のメソッドはクライアントに残っていますが、非推奨として示されます。code が voice_cloning_retired の NodaroError を、ステータス 410 でスローします。新しいカスタムボイスには、代わりに design() を使ってください。

client.voices:ボイスチェンジャー

voices.change(input)

録音や、話している動画全体の声を、別の声に置き換えます(POST /v1/voice-changer)。ボイスチェンジャー(Voice Changer)ノードと同じ処理です。videoUrl を指定すると、サーバーは動画から音声を取り出し、声を変換して、新しい声を元の映像に載せ直します。

change(input: {
  voiceId: string
  audioUrl?: string
  videoUrl?: string
  model?: string
  stability?: number
  similarityBoost?: number
  style?: number
  useSpeakerBoost?: boolean
  seed?: number
  removeBackgroundNoise?: boolean
}): Promise<{ jobId: string }>

Prop

Type

const { jobId } = await client.voices.change({
  videoUrl: "https://example.com/talking.mp4",
  voiceId: "Aria",
})
// the finished job's output_data has videoUrl and audioUrl

voices.recast(input)

録音の中で検出された各話者に、それぞれ異なるボイスを割り当てます(POST /v1/voice-changer-pro)。ボイスチェンジャー Pro(Voice Changer Pro)ノードと同じ処理です。Nodaro Cloud で実行され、クレジットがかかり、ジョブとして実行されます。

recast(input: VoiceChangerProInput): Promise<{ jobId: string }>

Prop

Type

orderedVoices の各エントリーは、次のいずれかです。

  • ボイス ID:"Rachel" のような標準ボイスの名前か、ElevenLabs のボイス ID です。
  • null:元の声を維持するスロットです。その話者は自分の声のままですが、それより後の話者は引き続き差し替えられます。差し替える話者にだけ料金がかかるため、維持するスロットは無料です。
  • オブジェクト:voiceId と、その話者の設定です。stability、similarityBoost、style は 0〜1、useSpeakerBoost、seed は 0〜4,294,967,295 です。volumeMode は "match"(デフォルト、元の話者のレベル)、"normalize"、または volume を 0〜200% で指定する "manual" のいずれかです。engine: "v3" は、録音した音声を変換する代わりに、その話者のセリフを文字起こしから読み上げ直します。[audio tags] にも対応します。

話者 0 には orderedVoices[0] が、話者 1 には orderedVoices[1] が割り当てられ、以降も同様です。最後のエントリーより後の話者は、自分の声のままです。声と音楽は、常に最初に分離されます。preserveBackground が決めるのは、音楽を戻すかどうかだけです。

voiceFx.preset は、リバーブの空間(room、bathroom、car、hall、concert-hall、church、cave、arena、outdoor)か、telephone、megaphone、echo、custom のいずれかです。リバーブのプリセットは、0〜100 の wetDryMix を使います。echo と custom は、20〜2,000 の delayMs と、0〜1 の decay を使います。

// Recast speakers 1 and 3, and keep speaker 2's own voice
const { jobId } = await client.voices.recast({
  audioUrl: "https://example.com/panel.mp3",
  orderedVoices: ["Rachel", null, "Aria"],
})

// Repeatable voices, a hall reverb, and finer separation
const { jobId: tuned } = await client.voices.recast({
  audioUrl: "https://example.com/dialogue.mp3",
  orderedVoices: [
    { voiceId: "Rachel", seed: 12345, stability: 0.6 },
    { voiceId: "Aria", seed: 67890, volumeMode: "manual", volume: 120 },
  ],
  voiceFx: { preset: "hall", wetDryMix: 35 },
  separationQuality: "best",
})

動画モードでは、完了したジョブの output_data に videoUrl と audioUrl が入ります。

voices.analyze(input)

クリップの話者を、差し替えずに検出します(POST /v1/voice-changer-pro/analyze)。声を音楽から 1 回分離し、誰がいつ話しているかを調べます。Nodaro Cloud で実行され、料金は一律で、ジョブとして実行されます。

analyze(input: {
  audioUrl?: string
  videoUrl?: string
  separationQuality?: "fast" | "best"
  suggestTitle?: boolean
}): Promise<{ jobId: string }>

Prop

Type

完了したジョブの output_data は VcpAnalysis です。分離した vocalsUrl と backgroundUrl、検出された speakers(それぞれに id、時間の segments、firstStartSec、wordCount、テキストの snippet を含む)、languageProbability を伴う languageCode、依頼した場合は suggestedTitle が含まれます。これを、後で呼び出す recast() に analysis として渡すと、分離済みのトラックが再利用され、検出のための料金がもう一度かかることはありません。

voices.exportMix(input)

ミックスしたステムから、最終的な動画をレンダリングします(POST /v1/voice-changer-pro/export)。recast({ output: "stems" }) の後に行う、最後のステップです。Nodaro Cloud で実行され、料金は一律で、ジョブとして実行されます。

exportMix(input: {
  videoUrl: string
  tracks: Array<{ url: string; gain: number; muted: boolean; kind?: "voice" | "background" }>
  voiceFx?: { preset: AudioFxPreset; wetDryMix?: number; delayMs?: number; decay?: number }
}): Promise<{ jobId: string }>

Prop

Type

対話的なフローでは、1 回分析し、ステムに差し替え、その後ミックスしてレンダリングします。以下は、簡単なポーリング用のヘルパーを使った例です。

import type { VcpAnalysis } from "@nodaro/sdk"

async function outputOf(jobId: string): Promise<any> {
  for (;;) {
    const { data } = await client.jobs.getStatus(jobId)
    if (data.status === "completed") return data.output_data
    if (data.status === "failed" || data.status === "cancelled") throw new Error(data.error_message ?? data.status)
    await new Promise((resolve) => setTimeout(resolve, 2_000))
  }
}

const { jobId: analyzeJob } = await client.voices.analyze({ videoUrl })
const analysis = (await outputOf(analyzeJob)) as VcpAnalysis

const { jobId: recastJob } = await client.voices.recast({
  videoUrl,
  orderedVoices: ["Rachel", null, "Aria"],
  output: "stems",
  analysis,
})
const stems = await outputOf(recastJob)

const { jobId: exportJob } = await client.voices.exportMix({
  videoUrl,
  tracks: [
    { url: stems.tracks[0].url, gain: 100, muted: false },
    { url: stems.tracks[1].url, gain: 90, muted: false },
    { url: stems.backgroundUrl, gain: 70, muted: false, kind: "background" },
  ],
  voiceFx: { preset: "hall", wetDryMix: 25 },
})
const { videoUrl: finalVideo } = await outputOf(exportJob)

ゲイン、ミュート、エフェクトは、動画をレンダリングするときに適用され、映像はそのままコピーされます。そのため、エクスポートの結果はプレビューと一致し、エクスポートするまでは、好きなだけミックスを変更できます。すべてのトラックをミュートしたミックスは、400 で拒否されます。

client.voices:作成と翻訳

voices.design(input)

文章による説明から、新しい合成ボイスを作成します(POST /v1/voice-design)。ボイスデザイン(Voice Design)ノードと同じ処理です。完了したジョブには、オーディオのプレビューと、新しいボイスの ID が含まれ、ボイスを指定できるところならどこでも使えます。

design(input: {
  text: string
  voiceDescription: string
  model?: string
  loudness?: number
  guidanceScale?: number
  seed?: number
  quality?: number
  shouldEnhance?: boolean
  userPrompt?: string
}): Promise<{ jobId: string }>

Prop

Type

const { jobId } = await client.voices.design({
  text: "Welcome back. Tonight we follow the river north, into the mountains where the story began.",
  voiceDescription: "A calm, deep voice of an older male narrator with a slight British accent",
})

voices.remix(input)

わかりやすい言葉で説明したボイスでテキストを話します。ボイスを作成することはありません(POST /v1/voice-remix)。ボイスリミックス(Voice Remix)ノードと同じ処理です。

remix(input: { text: string; voiceDescription: string; userPrompt?: string }): Promise<{ jobId: string }>

Prop

Type

const { jobId } = await client.voices.remix({
  text: "Your order is on its way.",
  voiceDescription: "A cheerful young woman, fast and upbeat",
})

voices.dub(input)

オーディオ、または動画全体を、各話者の声を保ったまま別の言語に吹き替えます(POST /v1/dubbing)。吹き替え(Dubbing)ノードと同じ処理です。動画の吹き替えでは、吹き替えたクリップである output_data.videoUrl と、吹き替えたトラックのみの output_data.audioUrl が返ります。

dub(input: DubbingInput): Promise<{ jobId: string }>

Prop

Type

const { jobId } = await client.voices.dub({
  videoUrl: "https://example.com/interview.mp4",
  targetLanguage: "es",
  numSpeakers: 2,
})

料金は、吹き替える区間の分数によって決まり、最低 1 分として計算されます。区間は最長 30 分なので、それより長いソースには startTime と endTime を使ってください。

voices.textToDialogue(input)

複数の話者による脚本を、1 つのオーディオファイルとして音声にします(POST /v1/text-to-dialogue)。テキストから会話(Text to Dialogue)ノードが ElevenLabs Dialogue v3 で行うのと同じ処理です。

textToDialogue(input: {
  dialogue: Array<{ text: string; voice: string }>
  stability?: 0 | 0.5 | 1
  languageCode?: string
  seed?: number
  applyTextNormalization?: "auto" | "on" | "off"
}): Promise<{ jobId: string }>

Prop

Type

const { jobId } = await client.voices.textToDialogue({
  dialogue: [
    { text: "Did you hear that?", voice: "Rachel" },
    { text: "[whispers] Stay behind me.", voice: "Callum" },
  ],
})

脚本は最大 5,000 文字まで使え、2,000 文字未満だと最も高品質になります。使えるボイスは最大 10 種類です。ボイスライブラリのボイス、デザインしたボイス、既存のクローンはどれも使えて、自由に組み合わせられます。完了したジョブの output_data.audioUrl が、そのファイルです。

client.audio

ボイスチェンジャー Pro が内部で使っているオーディオの構成要素で、1 つずつ個別に使えます。どのメソッドも jobId を返します。

audio.separate(input)

トラックをステムに分割します(POST /v1/audio-separation)。音源分離(Audio Separation)ノードと同じ処理です。

separate(input: { audioUrl: string; mode?: "vocal_instrumental" | "stems"; quality?: "auto" | "fast" | "best" }): Promise<{ jobId: string }>

Prop

Type

const { jobId } = await client.audio.separate({ audioUrl: songUrl })
// output: vocalUrl and instrumentalUrl, or one URL per stem in stems mode

audio.isolate(input)

主な声を残し、背景ノイズを取り除きます(POST /v1/audio-isolation)。音声抽出(Voice Extractor)ノードと同じ処理です。

isolate(input: { audioUrl: string }): Promise<{ jobId: string }>

Prop

Type

const { jobId } = await client.audio.isolate({ audioUrl: interviewUrl })

audio.applyFx(input)

リバーブ、エコー、電話、メガホンのエフェクトを加えます(POST /v1/audio-fx)。オーディオ FX(Audio FX)ノードと同じ処理です。プリセットは、ボイスチェンジャーの voiceFx と同じです。

applyFx(input: {
  audioUrl: string
  preset?: AudioFxPreset
  mix?: number
  delayMs?: number
  decay?: number
  eqLow?: number
  eqHigh?: number
}): Promise<{ jobId: string }>

Prop

Type

const { jobId } = await client.audio.applyFx({ audioUrl: lineUrl, preset: "telephone" })

audio.mix(input)

複数のトラックを重ねて 1 つにします(POST /v1/mix-audio)。オーディオをミックス(Mix Audio)ノードと同じ処理です。

mix(input: { audioUrls: string[]; trackVolumes?: number[] }): Promise<{ jobId: string }>

Prop

Type

const { jobId } = await client.audio.mix({ audioUrls: [voiceUrl, musicUrl], trackVolumes: [100, 35] })

audio.adjustVolume(input)

オーディオファイル、または動画の音の音量を変更します(POST /v1/adjust-volume)。音量調整(Adjust Volume)ノードと同じ処理です。

adjustVolume(input: {
  audioUrl?: string
  videoUrl?: string
  volume?: number
  normalize?: boolean
  fadeIn?: number
  fadeOut?: number
}): Promise<{ jobId: string }>

Prop

Type

const { jobId } = await client.audio.adjustVolume({ audioUrl: musicUrl, volume: 60, fadeOut: 3 })

audio.combine(input)

オーディオのセグメントを順番につなげます(POST /v1/combine-audio)。オーディオを結合(Combine Audio)ノードと同じ処理です。

combine(input: { segments: Array<{ url: string; startTime?: number; endTime?: number }> }): Promise<{ jobId: string }>

Prop

Type

const { jobId } = await client.audio.combine({
  segments: [{ url: introUrl }, { url: episodeUrl, startTime: 4 }, { url: outroUrl }],
})

audio.transcribe(input)

オーディオまたは動画ファイルの音声をテキストにします(POST /v1/transcribe)。文字起こし(Transcribe)ノードと同じ処理です。

transcribe(input: {
  audioUrl: string
  provider?: "elevenlabs-stt" | "incredibly-fast-whisper" | "whisper"
  language?: string
  diarize?: boolean
  tagAudioEvents?: boolean
  wordTimestamps?: boolean
}): Promise<{ jobId: string }>

Prop

Type

provider単語のタイミング備考
elevenlabs-stt常に返すdiarize と tagAudioEvents に対応する唯一のエンジンです。
incredibly-fast-whisperwordTimestamps: true のときだけこのフラグがない場合、ジョブは成功して課金されますが、フレーズ単位のセグメントのみで、words は空のリストになります。
whisper返さないフレーズ単位のセグメントのみです。wordTimestamps: true を指定すると、クレジットが使われる前に 400 validation_error で拒否されます。

provider を省略すると whisper が使われるため、provider を指定しない wordTimestamps: true も、同じ 400 になります。単語のタイミングが必要な場合は、elevenlabs-stt を指定するか、wordTimestamps: true を付けた incredibly-fast-whisper を指定してください。キネティックスタイルの字幕には、これが必要です。

const { jobId } = await client.audio.transcribe({ audioUrl: talkUrl, provider: "elevenlabs-stt" })

完了したジョブの output_data は TranscribeJobOutput です。

フィールド単位内容
text文字起こし全体を、1 つの文字列にしたものです。
language検出された、または指定した言語コードです。
wordsミリ秒単語ごとに 1 件で、{ text, startMs, endMs, speaker? } の形です。エンジンに単語のタイミングを求めなかった場合は空です。
jsonミリ秒正規化された文字起こしで、{ version, language, words, segments? } の形です。client.edit が受け取る形式です。
segments秒元のフレーズの範囲で、古いエンジンのみが返します。elevenlabs-stt は返さないので、words を読み取ってください。

words は、client.media.addCaptions() が受け取る captions と、まったく同じ形です。そのため、文字起こしを修正して、そのまま字幕として焼き込めます。

よくある質問

最終更新

目次