Make Studio 2 the home bench with YuE2 music, LTX, and per-preview hide.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+24
-183
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="min-h-dvh min-w-0">
|
||||
<AppHeader
|
||||
:subtitle="advanced ? headerSubtitle : 'Create music from text'"
|
||||
:subtitle="advanced ? 'YuE2 · lyrics-to-song' : 'Create music from text'"
|
||||
current="music"
|
||||
:queue-count="queueCount"
|
||||
/>
|
||||
@@ -10,9 +10,8 @@
|
||||
<StudioKindCards
|
||||
:advanced="advanced"
|
||||
current="music"
|
||||
:music-engine="engineFamily"
|
||||
music-engine="yue2"
|
||||
@select="goStudio"
|
||||
@music-engine="selectEngineFamily"
|
||||
/>
|
||||
<div class="flex items-center justify-between gap-3"><span class="rounded-full border border-amber-300/60 px-4 py-2 text-sm text-amber-100">From text</span><label class="flex items-center gap-2 text-sm text-zinc-300"><input v-model="advanced" type="checkbox" class="accent-amber-400">Advanced mode</label></div>
|
||||
<div class="grid min-w-0 gap-6 lg:grid-cols-[minmax(0,1fr)_minmax(0,1fr)] lg:items-stretch">
|
||||
@@ -20,43 +19,15 @@
|
||||
<div>
|
||||
<h2 class="font-display text-2xl font-bold">Music Generator</h2>
|
||||
<p class="mt-1 text-sm text-zinc-400">
|
||||
Tags describe style and voice. Lyrics use structure chips. Instrumental skips the vocal line.
|
||||
Tags describe style and voice. Lyrics use structure chips. Multiple sections are OK.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<GenerationSettings :advanced="advanced">
|
||||
<label class="block space-y-2 text-sm"><span>Model</span><select :value="engineFamily" class="w-full rounded-xl border border-white/15 bg-zinc-900 p-3" @change="selectEngineFamily(($event.target as HTMLSelectElement).value as 'ace' | 'yue' | 'yue2')"><option value="ace">ACE-Step</option><option value="yue">YuE</option><option value="yue2">YuE2</option></select></label>
|
||||
<label v-if="engineFamily === 'yue'" class="block space-y-2 text-sm">
|
||||
<span>YuEGP profile</span>
|
||||
<select v-model.number="yueProfile" class="w-full rounded-xl border border-white/15 bg-zinc-900 p-3">
|
||||
<option :value="1">1 · Full quality · 16GB (default)</option>
|
||||
<option :value="3">3 · Lower memory · Manual fallback</option>
|
||||
</select>
|
||||
<span class="block text-xs text-zinc-400">One lyric section. Compile off. Profile 3 is never selected automatically.</span>
|
||||
</label>
|
||||
<p v-else-if="engineFamily === 'yue2'" class="text-xs text-zinc-400">YuE2-3B · lyrics with section tags · plan → synthesize → decode · no score editor</p>
|
||||
<p class="text-xs text-zinc-400">YuE2-3B · lyrics with section tags · plan → synthesize → decode · no score editor</p>
|
||||
<div v-if="!advanced" class="space-y-4">
|
||||
<label v-if="engineFamily === 'ace'" class="block text-sm">Steps<input v-model.number="steps" type="number" :min="stepsMin" :max="stepsMax" class="mt-2 w-full rounded-xl border border-white/15 bg-zinc-900 p-3"></label>
|
||||
<label class="block text-sm">Seed<input v-model="seed" placeholder="random" class="mt-2 w-full rounded-xl border border-white/15 bg-zinc-900 p-3"></label>
|
||||
</div>
|
||||
<div v-if="engineFamily === 'ace'" class="flex items-center justify-between gap-3 rounded-2xl border border-white/10 bg-zinc-950/40 px-4 py-3 text-sm">
|
||||
<span class="min-w-0">
|
||||
<span class="flex items-center gap-2">
|
||||
<span class="block font-medium text-zinc-200">ACE-Step 1.5</span>
|
||||
<InfoTip
|
||||
aria-label="What ACE-Step 1.5 does"
|
||||
:text="ace15Info"
|
||||
/>
|
||||
</span>
|
||||
<span class="mt-0.5 block text-xs text-zinc-500">Turbo AIO checkpoint. Different graph than v1, usually 8 steps.</span>
|
||||
</span>
|
||||
<label class="relative inline-flex h-6 w-11 shrink-0 cursor-pointer items-center" title="Toggle ACE-Step 1.5">
|
||||
<input v-model="ace15" type="checkbox" class="peer sr-only" role="switch">
|
||||
<span class="absolute inset-0 rounded-full bg-zinc-700 transition peer-checked:bg-amber-400" />
|
||||
<span class="absolute left-0.5 top-0.5 h-5 w-5 rounded-full bg-white transition peer-checked:translate-x-5" />
|
||||
</label>
|
||||
</div>
|
||||
|
||||
</GenerationSettings>
|
||||
<p v-if="error" class="rounded-2xl border border-red-400/30 bg-red-400/10 px-4 py-3 text-sm text-red-200">{{ error }}</p>
|
||||
|
||||
@@ -73,18 +44,13 @@
|
||||
<div>
|
||||
<div class="mb-1 flex flex-wrap items-center justify-between gap-2">
|
||||
<span class="text-sm font-medium text-zinc-300">Lyrics</span>
|
||||
<label class="flex cursor-pointer items-center gap-2 text-xs text-zinc-400">
|
||||
<input v-model="instrumental" :disabled="engineFamily === 'yue' || engineFamily === 'yue2'" type="checkbox" class="accent-amber-400">
|
||||
Instrumental
|
||||
</label>
|
||||
</div>
|
||||
<div class="mb-2 flex flex-wrap gap-1.5">
|
||||
<button
|
||||
v-for="chip in chips"
|
||||
:key="chip"
|
||||
type="button"
|
||||
class="rounded-full border border-white/10 px-2.5 py-1 text-[11px] text-zinc-300 hover:border-amber-300/50 hover:text-white disabled:opacity-40"
|
||||
:disabled="instrumental"
|
||||
class="rounded-full border border-white/10 px-2.5 py-1 text-[11px] text-zinc-300 hover:border-amber-300/50 hover:text-white"
|
||||
@click="insertChip(chip)"
|
||||
>{{ chip }}</button>
|
||||
</div>
|
||||
@@ -92,8 +58,7 @@
|
||||
ref="lyricsEl"
|
||||
v-model="lyrics"
|
||||
rows="12"
|
||||
class="max-h-[min(28rem,50vh)] w-full overflow-y-auto rounded-2xl border border-white/10 bg-zinc-950/70 px-4 py-3 text-sm outline-none ring-amber-300/40 placeholder:text-zinc-600 [overflow-wrap:anywhere] focus:ring-2 disabled:opacity-50"
|
||||
:disabled="instrumental"
|
||||
class="max-h-[min(28rem,50vh)] w-full overflow-y-auto rounded-2xl border border-white/10 bg-zinc-950/70 px-4 py-3 text-sm outline-none ring-amber-300/40 placeholder:text-zinc-600 [overflow-wrap:anywhere] focus:ring-2"
|
||||
:placeholder="lyricsPlaceholder"
|
||||
/>
|
||||
</div>
|
||||
@@ -109,19 +74,7 @@
|
||||
:max="durationMax"
|
||||
step="5"
|
||||
>
|
||||
<span class="mt-1 block text-[11px] text-zinc-500">{{ engineFamily === 'yue' ? 'Approximate length · one lyric section' : engineFamily === 'yue2' ? 'Approximate length · multiple sections OK' : `${durationMin}–${durationMax} seconds` }}</span>
|
||||
</label>
|
||||
<label v-if="advanced && engineFamily === 'ace'" class="block text-sm">
|
||||
<span class="mb-1 block font-medium text-zinc-300">Steps · {{ steps }}</span>
|
||||
<input
|
||||
v-model.number="steps"
|
||||
type="range"
|
||||
class="aigen-slider w-full"
|
||||
:min="stepsMin"
|
||||
:max="stepsMax"
|
||||
step="1"
|
||||
>
|
||||
<span class="mt-1 block text-[11px] text-zinc-500">{{ ace15 ? '8 is the usual 1.5 turbo range' : '30–50 is the usual range' }}</span>
|
||||
<span class="mt-1 block text-[11px] text-zinc-500">Approximate length · multiple sections OK</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
@@ -209,7 +162,7 @@
|
||||
</div>
|
||||
<p v-if="busy && !queued && jobId" class="text-xs text-zinc-400">
|
||||
{{ musicElapsed }} elapsed · {{ musicActivityText }}
|
||||
<span v-if="(activeMusicEngine === 'yue' || activeMusicEngine === 'yue2') && !indeterminateMusic" class="mt-1 block">Progress is for the current stage.</span>
|
||||
<span v-if="!indeterminateMusic" class="mt-1 block">Progress is for the current stage.</span>
|
||||
<span v-if="indeterminateMusic" class="mt-1 block">Waiting for a progress report.</span>
|
||||
</p>
|
||||
<AudioPlayer
|
||||
@@ -236,18 +189,10 @@ const { advanced } = useStudioLayout()
|
||||
import {
|
||||
DEFAULT_MUSIC_LYRICS,
|
||||
DEFAULT_MUSIC_TAGS,
|
||||
MUSIC_CFG_DEFAULT,
|
||||
MUSIC_CFG_DEFAULT_15,
|
||||
MUSIC_DURATION_DEFAULT,
|
||||
MUSIC_DURATION_MAX,
|
||||
MUSIC_DURATION_MIN,
|
||||
MUSIC_STEPS_DEFAULT,
|
||||
MUSIC_STEPS_DEFAULT_15,
|
||||
MUSIC_STEPS_MAX,
|
||||
MUSIC_STEPS_MIN,
|
||||
MUSIC_STRUCTURE_CHIPS,
|
||||
parseMusicEngine,
|
||||
type MusicEngine,
|
||||
yueLyricsProblem,
|
||||
} from '~/utils/music'
|
||||
import { ensureGenerationNotifyPermission, notifyGenerationComplete } from '~/utils/generationNotify'
|
||||
@@ -259,25 +204,16 @@ const tagsPlaceholder = DEFAULT_MUSIC_TAGS
|
||||
const lyricsPlaceholder = DEFAULT_MUSIC_LYRICS
|
||||
const chips = MUSIC_STRUCTURE_CHIPS
|
||||
const durationMin = MUSIC_DURATION_MIN
|
||||
const durationMax = computed(() => (engineFamily.value === 'yue' || engineFamily.value === 'yue2') ? 150 : MUSIC_DURATION_MAX)
|
||||
const stepsMin = MUSIC_STEPS_MIN
|
||||
const stepsMax = MUSIC_STEPS_MAX
|
||||
|
||||
const ace15Info = 'Turns on ACE-Step 1.5 Turbo, the all-in-one checkpoint already on Beast. 1.5 uses a different Comfy graph than v1: a 1.5 text encoder (tags, BPM, key, duration) and EmptyAceStep1.5LatentAudio, usually with 8 sampler steps and CFG 1. Songs often come back faster and cleaner. Lyrics-strength from v1 does not apply. Leave this off to stay on ACE-Step v1 3.5B, which is the graph that already generated on this GPU.'
|
||||
const durationMax = MUSIC_DURATION_MAX
|
||||
|
||||
const tags = ref(DEFAULT_MUSIC_TAGS)
|
||||
const lyrics = ref(DEFAULT_MUSIC_LYRICS)
|
||||
const instrumental = ref(false)
|
||||
const duration = ref(MUSIC_DURATION_DEFAULT)
|
||||
const steps = ref(MUSIC_STEPS_DEFAULT)
|
||||
const seed = ref('')
|
||||
const name = ref('')
|
||||
const folderId = ref('')
|
||||
const folders = ref<LibraryFolder[]>([])
|
||||
const lyricsEl = ref<HTMLTextAreaElement | null>(null)
|
||||
const ace15 = ref(false)
|
||||
const engineFamily = ref<'ace' | 'yue' | 'yue2'>('ace')
|
||||
const yueProfile = ref<1 | 3>(1)
|
||||
const busy = ref(false)
|
||||
const forceClearing = ref(false)
|
||||
const error = ref('')
|
||||
@@ -285,10 +221,9 @@ const status = ref('')
|
||||
const progress = ref(0)
|
||||
const musicClock = ref(Date.now())
|
||||
const musicStartedAt = ref(0)
|
||||
const activeMusicEngine = ref('')
|
||||
const musicActivity = ref<{ checkedAt: number; running: boolean } | null>(null)
|
||||
let musicClockTimer: ReturnType<typeof setInterval> | null = null
|
||||
const indeterminateMusic = computed(() => !queued.value && (activeMusicEngine.value === 'yue' || activeMusicEngine.value === 'yue2') && progress.value < 98 && !musicActivity.value?.running)
|
||||
const indeterminateMusic = computed(() => !queued.value && progress.value < 98 && !musicActivity.value?.running)
|
||||
const recentMusicCheck = computed(() => Boolean(musicActivity.value?.running && musicClock.value - musicActivity.value.checkedAt < 15000))
|
||||
const musicElapsed = computed(() => {
|
||||
const seconds = musicStartedAt.value ? Math.max(0, Math.floor((musicClock.value - musicStartedAt.value) / 1000)) : 0
|
||||
@@ -318,64 +253,19 @@ let queuePoll: ReturnType<typeof setInterval> | null = null
|
||||
let recoverPoll: ReturnType<typeof setInterval> | null = null
|
||||
|
||||
const blocked = computed(() => Boolean(blockReason.value))
|
||||
const headerSubtitle = computed(() => {
|
||||
if (engineFamily.value === 'yue2') return 'YuE2 · lyrics-to-song'
|
||||
if (engineFamily.value === 'yue') return 'YuE · lyrics-to-song'
|
||||
return ace15.value ? 'ACE-Step 1.5 · vocals' : 'ACE-Step · vocals'
|
||||
})
|
||||
const selectedEngine = computed<MusicEngine>(() => {
|
||||
if (engineFamily.value === 'yue2') return 'yue2'
|
||||
if (engineFamily.value === 'yue') return 'yue'
|
||||
return ace15.value ? 'ace-step-1.5' : 'ace-step'
|
||||
})
|
||||
const blockReason = computed(() => {
|
||||
if (!folderId.value) return 'Choose a library folder before generating.'
|
||||
if ((engineFamily.value === 'yue' || engineFamily.value === 'yue2') && instrumental.value) return 'YuE requires lyrics. Use ACE for instrumental music.'
|
||||
if ((engineFamily.value === 'yue' || engineFamily.value === 'yue2') && duration.value > 150) return 'YuE supports up to 150 seconds per section.'
|
||||
if (duration.value > 150) return 'YuE2 supports up to 150 seconds.'
|
||||
if (!tags.value.trim()) return 'Add genre and style tags.'
|
||||
if (engineFamily.value === 'yue') { const problem = yueLyricsProblem(lyrics.value); if (problem) return problem }
|
||||
if (engineFamily.value === 'yue2' && !lyrics.value.trim()) return 'Write lyrics for YuE2.'
|
||||
if (!instrumental.value && !lyrics.value.trim()) return 'Write lyrics, or turn on Instrumental.'
|
||||
const problem = yueLyricsProblem(lyrics.value)
|
||||
if (problem) return problem
|
||||
return ''
|
||||
})
|
||||
|
||||
function selectEngineFamily(family: 'ace' | 'yue' | 'yue2') {
|
||||
engineFamily.value = family
|
||||
if (family === 'yue' || family === 'yue2') { instrumental.value = false; duration.value = Math.min(150, duration.value) }
|
||||
if (family === 'yue' && lyrics.value === DEFAULT_MUSIC_LYRICS) lyrics.value = '[Verse 1]\n'
|
||||
if (family === 'ace' && ace15.value && steps.value === MUSIC_STEPS_DEFAULT) {
|
||||
steps.value = MUSIC_STEPS_DEFAULT_15
|
||||
}
|
||||
if (family === 'ace' && !ace15.value && steps.value === MUSIC_STEPS_DEFAULT_15) {
|
||||
steps.value = MUSIC_STEPS_DEFAULT
|
||||
}
|
||||
}
|
||||
|
||||
function goStudio(kind: 'video' | 'image') {
|
||||
void navigateTo({ path: '/', query: { studio: kind } })
|
||||
}
|
||||
|
||||
function applyEngine(engine: MusicEngine) {
|
||||
if (engine === 'yue2') {
|
||||
engineFamily.value = 'yue2'
|
||||
ace15.value = false
|
||||
return
|
||||
}
|
||||
if (engine === 'yue') {
|
||||
engineFamily.value = 'yue'
|
||||
ace15.value = false
|
||||
return
|
||||
}
|
||||
engineFamily.value = 'ace'
|
||||
ace15.value = engine === 'ace-step-1.5'
|
||||
}
|
||||
|
||||
watch(ace15, (on) => {
|
||||
if (engineFamily.value !== 'ace') return
|
||||
if (on && (steps.value === MUSIC_STEPS_DEFAULT || steps.value >= 30)) steps.value = MUSIC_STEPS_DEFAULT_15
|
||||
if (!on && steps.value === MUSIC_STEPS_DEFAULT_15) steps.value = MUSIC_STEPS_DEFAULT
|
||||
})
|
||||
|
||||
function insertChip(chip: string) {
|
||||
const el = lyricsEl.value
|
||||
const token = `${chip}\n`
|
||||
@@ -461,11 +351,7 @@ async function attachLiveMusic(opts: {
|
||||
if (typeof opts.progress === 'number') progress.value = opts.progress
|
||||
if (opts.message) status.value = opts.message
|
||||
else if (!status.value || /queueing|waiting for a generate|waiting in the job queue|waiting for gpu/i.test(status.value)) {
|
||||
status.value = selectedEngine.value === 'yue'
|
||||
? 'YuEGP is generating your song'
|
||||
: selectedEngine.value === 'yue2'
|
||||
? 'YuE2 is generating your song'
|
||||
: 'Generating…'
|
||||
status.value = 'YuE2 is generating your song'
|
||||
}
|
||||
if (jobId.value !== liveId) {
|
||||
musicActivity.value = null
|
||||
@@ -508,11 +394,7 @@ async function refreshStudioQueue() {
|
||||
busy.value = true
|
||||
status.value = musicRow.status === 'held'
|
||||
? 'Paused in the job queue'
|
||||
: (selectedEngine.value === 'yue'
|
||||
? 'Waiting for the GPU to run YuEGP'
|
||||
: selectedEngine.value === 'yue2'
|
||||
? 'Waiting for the GPU to run YuE2'
|
||||
: 'Waiting in the job queue…')
|
||||
: 'Waiting for the GPU to run YuE2'
|
||||
}
|
||||
|
||||
if (!studioJobId.value) return
|
||||
@@ -522,11 +404,7 @@ async function refreshStudioQueue() {
|
||||
queued.value = false
|
||||
}
|
||||
if (jobId.value && /waiting in the job queue/i.test(status.value)) {
|
||||
status.value = selectedEngine.value === 'yue'
|
||||
? 'YuEGP is generating your song'
|
||||
: selectedEngine.value === 'yue2'
|
||||
? 'YuE2 is generating your song'
|
||||
: 'Generating…'
|
||||
status.value = 'YuE2 is generating your song'
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -535,11 +413,7 @@ async function refreshStudioQueue() {
|
||||
busy.value = true
|
||||
status.value = row.status === 'held'
|
||||
? 'Paused in the job queue'
|
||||
: (selectedEngine.value === 'yue'
|
||||
? 'Waiting for the GPU to run YuEGP'
|
||||
: selectedEngine.value === 'yue2'
|
||||
? 'Waiting for the GPU to run YuE2'
|
||||
: 'Waiting in the job queue…')
|
||||
: 'Waiting for the GPU to run YuE2'
|
||||
return
|
||||
}
|
||||
if (row.status === 'running' && row.liveJobId) {
|
||||
@@ -574,7 +448,6 @@ async function resumeActiveMusic() {
|
||||
|
||||
function applyEvent(payload: Record<string, any>) {
|
||||
if (typeof payload.elapsedMs === 'number') musicStartedAt.value = Date.now() - payload.elapsedMs
|
||||
if (payload.engine) activeMusicEngine.value = payload.engine
|
||||
if (payload.musicActivity) musicActivity.value = payload.musicActivity
|
||||
if (payload.message) status.value = payload.message
|
||||
if (typeof payload.progress === 'number') progress.value = payload.progress
|
||||
@@ -682,13 +555,7 @@ async function generate() {
|
||||
trackId.value = ''
|
||||
jobId.value = ''
|
||||
studioJobId.value = ''
|
||||
status.value = engineFamily.value === 'yue'
|
||||
? 'Queueing YuE…'
|
||||
: engineFamily.value === 'yue2'
|
||||
? 'Queueing YuE2…'
|
||||
: ace15.value
|
||||
? 'Queueing ACE-Step 1.5…'
|
||||
: 'Queueing ACE-Step…'
|
||||
status.value = 'Queueing YuE2…'
|
||||
try {
|
||||
const started = await $fetch<{ jobId: string; studioJobId?: string; queued?: boolean; name?: string }>(
|
||||
'/api/generate/music',
|
||||
@@ -698,14 +565,10 @@ async function generate() {
|
||||
tags: tags.value,
|
||||
lyrics: lyrics.value,
|
||||
duration: duration.value,
|
||||
steps: steps.value,
|
||||
seed: seed.value || 'random',
|
||||
cfg: selectedEngine.value === 'ace-step-1.5' ? MUSIC_CFG_DEFAULT_15 : MUSIC_CFG_DEFAULT,
|
||||
instrumental: instrumental.value,
|
||||
folderId: folderId.value,
|
||||
name: name.value.trim(),
|
||||
engine: selectedEngine.value,
|
||||
...(engineFamily.value === 'yue' ? { yueProfile: yueProfile.value } : {})
|
||||
engine: 'yue2'
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -731,10 +594,6 @@ async function generate() {
|
||||
}
|
||||
}
|
||||
|
||||
watch(instrumental, (on) => {
|
||||
if (on && !lyrics.value.trim()) lyrics.value = DEFAULT_MUSIC_LYRICS
|
||||
})
|
||||
|
||||
function applyIncomingMusic() {
|
||||
try {
|
||||
const genRaw = sessionStorage.getItem(LOAD_GENERATION_PAYLOAD_KEY)
|
||||
@@ -745,14 +604,10 @@ function applyIncomingMusic() {
|
||||
const payload = loaded.payload
|
||||
if (typeof payload.prompt === 'string') tags.value = payload.prompt
|
||||
if (typeof payload.lyrics === 'string') lyrics.value = payload.lyrics
|
||||
instrumental.value = payload.instrumental === true
|
||||
if (typeof payload.duration === 'number') duration.value = payload.duration
|
||||
if (typeof payload.steps === 'number') steps.value = payload.steps
|
||||
if (typeof payload.duration === 'number') duration.value = Math.min(MUSIC_DURATION_MAX, payload.duration)
|
||||
if (payload.seed != null) seed.value = String(payload.seed)
|
||||
if (typeof payload.name === 'string') name.value = payload.name
|
||||
if (payload.folderId && folders.value.some(folder => folder.id === payload.folderId)) folderId.value = payload.folderId
|
||||
if (payload.yueProfile === 1 || payload.yueProfile === 3) yueProfile.value = payload.yueProfile
|
||||
if (payload.musicEngine || payload.engine) applyEngine(parseMusicEngine(payload.musicEngine || payload.engine))
|
||||
status.value = 'Loaded from generation log'
|
||||
return
|
||||
}
|
||||
@@ -767,24 +622,16 @@ function applyIncomingMusic() {
|
||||
name?: string
|
||||
tags?: string
|
||||
lyrics?: string
|
||||
instrumental?: boolean
|
||||
duration?: number
|
||||
steps?: number
|
||||
seed?: string
|
||||
folderId?: string
|
||||
engine?: string
|
||||
yueProfile?: 1 | 3
|
||||
}
|
||||
if (typeof loaded.tags === 'string') tags.value = loaded.tags
|
||||
if (typeof loaded.lyrics === 'string') lyrics.value = loaded.lyrics
|
||||
instrumental.value = loaded.instrumental === true
|
||||
if (typeof loaded.duration === 'number') duration.value = loaded.duration
|
||||
if (typeof loaded.steps === 'number') steps.value = loaded.steps
|
||||
if (typeof loaded.duration === 'number') duration.value = Math.min(MUSIC_DURATION_MAX, loaded.duration)
|
||||
if (typeof loaded.seed === 'string') seed.value = loaded.seed
|
||||
if (typeof loaded.name === 'string') name.value = loaded.name
|
||||
if (loaded.folderId && folders.value.some(folder => folder.id === loaded.folderId)) folderId.value = loaded.folderId
|
||||
if (loaded.engine) applyEngine(parseMusicEngine(loaded.engine))
|
||||
yueProfile.value = loaded.yueProfile === 3 ? 3 : 1
|
||||
status.value = 'Loaded from the queue'
|
||||
} catch { /* ignore */ }
|
||||
}
|
||||
@@ -800,12 +647,8 @@ function applyPreset() {
|
||||
const settings = preset.settings as MusicPresetSettings
|
||||
if (typeof settings.tags === 'string') tags.value = settings.tags
|
||||
if (typeof settings.lyrics === 'string') lyrics.value = settings.lyrics
|
||||
instrumental.value = settings.instrumental === true
|
||||
if (typeof settings.duration === 'number') duration.value = settings.duration
|
||||
if (typeof settings.steps === 'number') steps.value = settings.steps
|
||||
if (typeof settings.duration === 'number') duration.value = Math.min(MUSIC_DURATION_MAX, settings.duration)
|
||||
if (typeof settings.seed === 'number') seed.value = String(settings.seed)
|
||||
if (settings.engine) applyEngine(settings.engine)
|
||||
yueProfile.value = settings.yueProfile === 3 ? 3 : 1
|
||||
name.value = preset.name
|
||||
}
|
||||
|
||||
@@ -813,14 +656,12 @@ onMounted(async () => {
|
||||
musicClockTimer = setInterval(() => { musicClock.value = Date.now() }, 1000)
|
||||
await loadLibrary()
|
||||
await loadMusicPresets()
|
||||
const route = useRoute()
|
||||
const engineQ = String(route.query.engine || '').toLowerCase()
|
||||
if (engineQ === 'yue' || engineQ === 'yue2' || engineQ === 'ace') selectEngineFamily(engineQ as 'ace' | 'yue' | 'yue2')
|
||||
applyIncomingMusic()
|
||||
await resumeActiveMusic()
|
||||
await refreshStudioQueue()
|
||||
stopQueuePoll()
|
||||
queuePoll = setInterval(() => { void refreshStudioQueue() }, 8000)
|
||||
const route = useRoute()
|
||||
const query = route.query
|
||||
if (typeof query.track === 'string' && query.track) {
|
||||
audioUrl.value = `/api/library/tracks/${query.track}/audio`
|
||||
@@ -834,7 +675,7 @@ onMounted(async () => {
|
||||
if (recovered?.trackId && /recovered/i.test(String(recovered.message || ''))) {
|
||||
applyEvent({ ...recovered, type: 'complete' })
|
||||
}
|
||||
} catch { /* nothing waiting in ComfyUI */ }
|
||||
} catch { /* nothing waiting */ }
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user