sonilo 0.15.0 → 0.16.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +48 -1
- package/dist/index.cjs +14 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +53 -7
- package/dist/index.d.ts +53 -7
- package/dist/index.js +14 -8
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -127,6 +127,53 @@ if (result.ducked) {
|
|
|
127
127
|
}
|
|
128
128
|
```
|
|
129
129
|
|
|
130
|
+
### Stems (async)
|
|
131
|
+
|
|
132
|
+
Set `stems: true` to also split the generated track into four separated
|
|
133
|
+
stems — `drums`, `bass`, `vocals`, `other`. It is **free of charge**, and
|
|
134
|
+
available on `textToMusic` and `videoToMusic`. It requires the async task API
|
|
135
|
+
(`mode: "async"` — the backend rejects it on the plain stream with a 400), so
|
|
136
|
+
it is only meaningful via `submit()`; on `videoToMusic` it splits the
|
|
137
|
+
**generated** music, never the source video's own audio.
|
|
138
|
+
|
|
139
|
+
When separation succeeds, the result gains a `stems` array with one entry per
|
|
140
|
+
stream: `{ stream_index, drums, bass, vocals, other }`, each stem an ordinary
|
|
141
|
+
media object (`url`, `content_type`, `file_size`) you can pass to
|
|
142
|
+
`download()`. **Look entries up by `stream_index`, never by array position** —
|
|
143
|
+
`stems` carries only the streams that separated successfully, so it can be
|
|
144
|
+
shorter than `audio`.
|
|
145
|
+
|
|
146
|
+
Failures land in `stems_error`, a string present when separation failed wholly
|
|
147
|
+
or in part, or was skipped. It can appear **alongside a partial `stems`
|
|
148
|
+
array**, so never treat it as "no stems" — check `stems` itself for what did
|
|
149
|
+
arrive. Either way the generated `audio` is unaffected.
|
|
150
|
+
|
|
151
|
+
Separation runs after generation and typically adds 2-6 minutes to the wait
|
|
152
|
+
(it gives up after 30), so raise `tasks.wait`'s `timeout` beyond the 10-minute
|
|
153
|
+
default. The stems normally follow the request's `outputFormat`; each stem's
|
|
154
|
+
own `content_type` reports what was actually delivered.
|
|
155
|
+
|
|
156
|
+
```ts
|
|
157
|
+
const task = await client.textToMusic.submit({
|
|
158
|
+
prompt: "warm lo-fi piano",
|
|
159
|
+
duration: 30,
|
|
160
|
+
stems: true, // free — adds drums/bass/vocals/other alongside the mix
|
|
161
|
+
});
|
|
162
|
+
const result = await client.tasks.wait<MusicTaskResult>(task.task_id, {
|
|
163
|
+
timeout: 2_400_000, // separation can add up to 30 minutes
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
if (result.stems_error) console.warn(result.stems_error); // may be partial
|
|
167
|
+
for (const track of result.audio ?? []) {
|
|
168
|
+
const split = result.stems?.find((s) => s.stream_index === track.stream_index);
|
|
169
|
+
if (!split) continue; // this stream did not separate — see stems_error
|
|
170
|
+
await writeFile("drums.m4a", await download(split.drums));
|
|
171
|
+
await writeFile("bass.m4a", await download(split.bass));
|
|
172
|
+
await writeFile("vocals.m4a", await download(split.vocals));
|
|
173
|
+
await writeFile("other.m4a", await download(split.other));
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
130
177
|
### Variants (async)
|
|
131
178
|
|
|
132
179
|
`variantsNum` generates several distinct music variants in one request (1-10,
|
|
@@ -329,7 +376,7 @@ boolean (default off, free) ducks the background music/effects bed under the
|
|
|
329
376
|
dubbed voice while it speaks; when off the bed is kept at a constant level.
|
|
330
377
|
Every endpoint's `ducking` is default-off, so this one is no exception.
|
|
331
378
|
|
|
332
|
-
Dubbing is async-only, and the source video may be at most
|
|
379
|
+
Dubbing is async-only, and the source video may be at most 300 seconds long.
|
|
333
380
|
You are billed per language. Dubbing has **no free trial allowance** — unlike
|
|
334
381
|
every other endpoint, every call bills from the first one (see
|
|
335
382
|
[Free trial](#free-trial)).
|
package/dist/index.cjs
CHANGED
|
@@ -347,8 +347,8 @@ var TextToMusic = class {
|
|
|
347
347
|
/**
|
|
348
348
|
* Submit an async text-to-music task; poll with
|
|
349
349
|
* `client.tasks.wait<MusicTaskResult>(task.task_id)`. Required for
|
|
350
|
-
* a non-m4a `outputFormat
|
|
351
|
-
* remain the streaming path.
|
|
350
|
+
* a non-m4a `outputFormat`, `variantsNum` above 1, and `stems`.
|
|
351
|
+
* `stream()`/`generate()` remain the streaming path.
|
|
352
352
|
*/
|
|
353
353
|
async submit(params) {
|
|
354
354
|
const mode = params.mode ?? "async";
|
|
@@ -368,6 +368,9 @@ var TextToMusic = class {
|
|
|
368
368
|
if (params.variantsNum !== void 0) {
|
|
369
369
|
form.set("variants_num", String(params.variantsNum));
|
|
370
370
|
}
|
|
371
|
+
if (params.stems !== void 0) {
|
|
372
|
+
form.set("stems", String(params.stems));
|
|
373
|
+
}
|
|
371
374
|
const res = await this.client.request("/v1/text-to-music", {
|
|
372
375
|
method: "POST",
|
|
373
376
|
body: form
|
|
@@ -451,9 +454,9 @@ var VideoToMusic = class {
|
|
|
451
454
|
/**
|
|
452
455
|
* Submit an async video-to-music task; poll its result with
|
|
453
456
|
* `client.tasks.wait<MusicTaskResult>(task.task_id)`. Required for
|
|
454
|
-
* `isolateVocals`/`preserveSpeech`, a non-m4a `outputFormat`,
|
|
455
|
-
* `variantsNum` above 1 — the backend rejects all of these on
|
|
456
|
-
* stream, and they only ever run in async mode.
|
|
457
|
+
* `isolateVocals`/`preserveSpeech`, a non-m4a `outputFormat`,
|
|
458
|
+
* `variantsNum` above 1, and `stems` — the backend rejects all of these on
|
|
459
|
+
* the plain stream, and they only ever run in async mode.
|
|
457
460
|
*/
|
|
458
461
|
async submit(params) {
|
|
459
462
|
if (params.video === void 0 === (params.videoUrl === void 0)) {
|
|
@@ -463,11 +466,11 @@ var VideoToMusic = class {
|
|
|
463
466
|
const needsAsync = params.isolateVocals || params.preserveSpeech || params.ducking !== void 0 || // Any non-m4a container is a finalize-time transcode, so it needs
|
|
464
467
|
// async. Checking != "m4a" rather than == "wav" keeps this correct
|
|
465
468
|
// as formats are added (mp3 landed after the original check).
|
|
466
|
-
params.outputFormat !== void 0 && params.outputFormat !== "m4a" || params.variantsNum !== void 0 && params.variantsNum > 1;
|
|
469
|
+
params.outputFormat !== void 0 && params.outputFormat !== "m4a" || params.variantsNum !== void 0 && params.variantsNum > 1 || params.stems !== void 0;
|
|
467
470
|
if (mode === void 0) mode = "async";
|
|
468
471
|
if (needsAsync && mode !== "async") {
|
|
469
472
|
throw new SoniloError(
|
|
470
|
-
'isolateVocals/preserveSpeech/ducking/outputFormat other than "m4a"/variantsNum > 1 require mode: "async"'
|
|
473
|
+
'isolateVocals/preserveSpeech/ducking/stems/outputFormat other than "m4a"/variantsNum > 1 require mode: "async"'
|
|
471
474
|
);
|
|
472
475
|
}
|
|
473
476
|
const form = new FormData();
|
|
@@ -497,6 +500,9 @@ var VideoToMusic = class {
|
|
|
497
500
|
if (params.variantsNum !== void 0) {
|
|
498
501
|
form.set("variants_num", String(params.variantsNum));
|
|
499
502
|
}
|
|
503
|
+
if (params.stems !== void 0) {
|
|
504
|
+
form.set("stems", String(params.stems));
|
|
505
|
+
}
|
|
500
506
|
if (params.promptInfluence !== void 0) {
|
|
501
507
|
form.set("prompt_influence", String(params.promptInfluence));
|
|
502
508
|
}
|
|
@@ -825,7 +831,7 @@ var VideoAnalysis = class {
|
|
|
825
831
|
};
|
|
826
832
|
|
|
827
833
|
// src/version.ts
|
|
828
|
-
var VERSION = "0.
|
|
834
|
+
var VERSION = "0.16.1";
|
|
829
835
|
|
|
830
836
|
// src/client.ts
|
|
831
837
|
var DEFAULT_BASE_URL = "https://api.sonilo.com";
|