- audio.StemSeparator/StemSeparationProvider: Demucs zip transport via POST /upstream/<id>/v1/stems (Mode two -> two_stems=vocals; model + format fields); bounded zip unpack, entry name -> stem, ext -> MIME. - SFXModel reuses musicgen against the sync /upstream/<id>/v1/sfx route (JSON prompt/seconds/steps/cfg_scale/seed -> WAV); musicgen.Request gains CFGScale. - audio.SpeechEnhancer/SpeechEnhancementProvider: POST /upstream/<id>/v1/enhance -> WAV (result reuses SpeechResult). - SpeechRequest.ReferenceAudio/ReferenceMIME (+WithReferenceAudio): llamaswap switches to the chatterbox clone route POST /upstream/<id>/v1/audio/speech/upload (input + voice_file), wav MIME fallback. - TranscriptionRequest.Translate (+WithTranslate): translate=true form field, language=auto forced when no explicit hint (whisper.cpp default en would skip translation). - httptest contract tests (zip unpack, clone-route switch, translate + auto-language injection); ADR-0024 (index row deferred — MJ-A backfills the ADR index table and parallel edits would conflict). Co-Authored-By: Claude Fable 5 <[email protected]>
114 lines
3.7 KiB
Go
114 lines
3.7 KiB
Go
package audio
|
|
|
|
import "context"
|
|
|
|
// StemSeparationRequest asks a source-separation backend (Demucs style) to
|
|
// split a mix into stems. Audio is carried as bytes (never a URL), mirroring
|
|
// TranscriptionRequest. Zero values mean "backend default" (ADR-0024).
|
|
type StemSeparationRequest struct {
|
|
// Audio is the encoded mix to separate.
|
|
Audio []byte
|
|
|
|
// MIME is the audio MIME type (e.g. "audio/mpeg"); "" = let the backend
|
|
// sniff it.
|
|
MIME string
|
|
|
|
// Filename is the multipart filename hint some backends key their format
|
|
// detection on; "" derives one from MIME or falls back to "audio".
|
|
Filename string
|
|
|
|
// Mode selects the split: "two" (vocals + accompaniment) or "four"
|
|
// (vocals/drums/bass/other); "" = backend default (four).
|
|
Mode string
|
|
|
|
// Model selects the separator's internal network where the backend
|
|
// offers several (Demucs: "htdemucs", "htdemucs_ft"); "" = backend
|
|
// default. This is NOT the provider model id — that is fixed when the
|
|
// StemSeparator is minted (mirrors BackgroundRemovalRequest.Net).
|
|
Model string
|
|
|
|
// Format is the per-stem audio container ("mp3" or "wav");
|
|
// "" = backend default.
|
|
Format string
|
|
}
|
|
|
|
// Stem is one separated source.
|
|
type Stem struct {
|
|
// Name is the stem's name ("vocals", "drums", "bass", "other",
|
|
// "no_vocals", ...), taken from the backend's own labelling.
|
|
Name string
|
|
|
|
// Audio is the encoded stem.
|
|
Audio []byte
|
|
|
|
// MIME is the stem's audio MIME type, e.g. "audio/mpeg".
|
|
MIME string
|
|
}
|
|
|
|
// StemSeparationResult is the canonical separation result.
|
|
type StemSeparationResult struct {
|
|
// Stems are the separated sources, in the order the backend returned
|
|
// them.
|
|
Stems []Stem
|
|
}
|
|
|
|
// StemSeparationOption mutates a StemSeparationRequest before it is sent.
|
|
type StemSeparationOption func(*StemSeparationRequest)
|
|
|
|
// WithStemMode selects the split ("two" or "four").
|
|
func WithStemMode(m string) StemSeparationOption {
|
|
return func(r *StemSeparationRequest) { r.Mode = m }
|
|
}
|
|
|
|
// WithStemModel selects the separator's internal network.
|
|
func WithStemModel(m string) StemSeparationOption {
|
|
return func(r *StemSeparationRequest) { r.Model = m }
|
|
}
|
|
|
|
// WithStemFormat sets the per-stem audio container ("mp3", "wav").
|
|
func WithStemFormat(f string) StemSeparationOption {
|
|
return func(r *StemSeparationRequest) { r.Format = f }
|
|
}
|
|
|
|
// Apply returns a copy of the request with all options applied.
|
|
func (r StemSeparationRequest) Apply(opts ...StemSeparationOption) StemSeparationRequest {
|
|
for _, opt := range opts {
|
|
opt(&r)
|
|
}
|
|
return r
|
|
}
|
|
|
|
// StemSeparator splits a mix into stems.
|
|
type StemSeparator interface {
|
|
// SeparateStems returns the separated sources. Separation is CPU-bound
|
|
// and slow (minutes for a full song); bound the call with a context
|
|
// deadline.
|
|
SeparateStems(ctx context.Context, req StemSeparationRequest, opts ...StemSeparationOption) (*StemSeparationResult, error)
|
|
}
|
|
|
|
// StemSeparatorModelOption configures a StemSeparator at construction time.
|
|
// Reserved for future per-model settings.
|
|
type StemSeparatorModelOption func(*StemSeparatorModelConfig)
|
|
|
|
// StemSeparatorModelConfig carries per-model construction settings.
|
|
type StemSeparatorModelConfig struct{}
|
|
|
|
// ApplyStemSeparatorModelOptions folds options into a config.
|
|
func ApplyStemSeparatorModelOptions(opts []StemSeparatorModelOption) StemSeparatorModelConfig {
|
|
var cfg StemSeparatorModelConfig
|
|
for _, opt := range opts {
|
|
opt(&cfg)
|
|
}
|
|
return cfg
|
|
}
|
|
|
|
// StemSeparationProvider mints StemSeparators bound to one backend.
|
|
type StemSeparationProvider interface {
|
|
// Name is the registry identifier for the provider.
|
|
Name() string
|
|
|
|
// StemSeparatorModel returns a StemSeparator bound to the given id
|
|
// (passed through to the backend verbatim; no catalog validation).
|
|
StemSeparatorModel(id string, opts ...StemSeparatorModelOption) (StemSeparator, error)
|
|
}
|