Add ACE-Step music generation to the studio and library.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
export const MUSIC_DURATION_MIN = 30
|
||||
export const MUSIC_DURATION_MAX = 180
|
||||
export const MUSIC_DURATION_DEFAULT = 60
|
||||
export const MUSIC_STEPS_MIN = 8
|
||||
export const MUSIC_STEPS_MAX = 100
|
||||
export const MUSIC_STEPS_DEFAULT = 50
|
||||
export const MUSIC_CFG_DEFAULT = 5
|
||||
export const MUSIC_LYRICS_STRENGTH_DEFAULT = 0.9
|
||||
export const MUSIC_TAGS_MAX = 2000
|
||||
export const MUSIC_LYRICS_MAX = 8000
|
||||
|
||||
export const MUSIC_STRUCTURE_CHIPS = [
|
||||
'[Verse 1]',
|
||||
'[Verse 2]',
|
||||
'[Pre-Chorus]',
|
||||
'[Chorus]',
|
||||
'[Bridge]',
|
||||
'[Guitar Solo]',
|
||||
'[Instrumental]',
|
||||
'[Outro]'
|
||||
] as const
|
||||
|
||||
export const DEFAULT_MUSIC_TAGS = 'modern synthpop, 120 bpm, female vocals, punchy bass, analog synths'
|
||||
|
||||
export const DEFAULT_MUSIC_LYRICS = `[Verse 1]
|
||||
|
||||
[Chorus]
|
||||
|
||||
[Guitar Solo]
|
||||
|
||||
[Outro]
|
||||
`
|
||||
|
||||
export type MusicEngine = 'ace-step' | 'ace-step-1.5'
|
||||
|
||||
export function parseMusicEngine(raw: unknown): MusicEngine {
|
||||
const value = String(raw || '').trim().toLowerCase()
|
||||
if (value === 'ace-step-1.5' || value === 'ace15' || value === 'v1.5') return 'ace-step-1.5'
|
||||
return 'ace-step'
|
||||
}
|
||||
|
||||
export function clampMusicDuration(raw: unknown, fallback = MUSIC_DURATION_DEFAULT) {
|
||||
const value = Number(raw)
|
||||
if (!Number.isFinite(value)) return fallback
|
||||
return Math.min(MUSIC_DURATION_MAX, Math.max(MUSIC_DURATION_MIN, Math.round(value)))
|
||||
}
|
||||
|
||||
export function clampMusicSteps(raw: unknown, fallback = MUSIC_STEPS_DEFAULT) {
|
||||
const value = Number(raw)
|
||||
if (!Number.isFinite(value)) return fallback
|
||||
return Math.min(MUSIC_STEPS_MAX, Math.max(MUSIC_STEPS_MIN, Math.round(value)))
|
||||
}
|
||||
|
||||
export function clampMusicCfg(raw: unknown, fallback = MUSIC_CFG_DEFAULT) {
|
||||
const value = Number(raw)
|
||||
if (!Number.isFinite(value)) return fallback
|
||||
return Math.min(15, Math.max(1, Math.round(value * 10) / 10))
|
||||
}
|
||||
|
||||
export function clampLyricsStrength(raw: unknown, fallback = MUSIC_LYRICS_STRENGTH_DEFAULT) {
|
||||
const value = Number(raw)
|
||||
if (!Number.isFinite(value)) return fallback
|
||||
return Math.min(2, Math.max(0, Math.round(value * 100) / 100))
|
||||
}
|
||||
|
||||
export function sanitizeMusicTags(raw: unknown) {
|
||||
return String(raw || '').replace(/\r\n/g, '\n').trim().slice(0, MUSIC_TAGS_MAX)
|
||||
}
|
||||
|
||||
export function sanitizeMusicLyrics(raw: unknown, instrumental = false) {
|
||||
if (instrumental) return ''
|
||||
return String(raw || '').replace(/\r\n/g, '\n').trim().slice(0, MUSIC_LYRICS_MAX)
|
||||
}
|
||||
|
||||
export function parseMusicSeed(raw: unknown) {
|
||||
const text = String(raw ?? '').trim().toLowerCase()
|
||||
if (!text || text === 'random') return Math.floor(Math.random() * 2_147_483_647)
|
||||
const value = Number(text)
|
||||
if (!Number.isFinite(value)) return Math.floor(Math.random() * 2_147_483_647)
|
||||
return Math.max(0, Math.min(2_147_483_647, Math.floor(value)))
|
||||
}
|
||||
|
||||
export function musicContentType(ext: string) {
|
||||
const kind = String(ext || '').replace(/^\./, '').toLowerCase()
|
||||
if (kind === 'wav') return 'audio/wav'
|
||||
if (kind === 'flac') return 'audio/flac'
|
||||
if (kind === 'mp3') return 'audio/mpeg'
|
||||
if (kind === 'ogg' || kind === 'opus') return 'audio/ogg'
|
||||
return 'application/octet-stream'
|
||||
}
|
||||
|
||||
export function musicExtension(filename: string) {
|
||||
const match = String(filename || '').toLowerCase().match(/\.(wav|flac|mp3|ogg|opus)$/)
|
||||
return match ? match[1] : 'flac'
|
||||
}
|
||||
Reference in New Issue
Block a user