mirror of
https://github.com/jamiepine/voicebox.git
synced 2026-09-18 22:30:40 -07:00
feat: add chunk crossfade slider (0ms = hard cut)
Persisted setting (default 50ms) controls how audio chunks are blended together. Set to 0 for a clean hard cut with no overlap.
This commit is contained in:
@@ -36,6 +36,8 @@ export function ConnectionForm() {
|
||||
const setMode = useServerStore((state) => state.setMode);
|
||||
const maxChunkChars = useServerStore((state) => state.maxChunkChars);
|
||||
const setMaxChunkChars = useServerStore((state) => state.setMaxChunkChars);
|
||||
const crossfadeMs = useServerStore((state) => state.crossfadeMs);
|
||||
const setCrossfadeMs = useServerStore((state) => state.setCrossfadeMs);
|
||||
const { toast } = useToast();
|
||||
|
||||
const form = useForm<ConnectionFormValues>({
|
||||
@@ -177,6 +179,29 @@ export function ConnectionForm() {
|
||||
can improve quality for long outputs. Default is 800.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="space-y-3 mt-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<label htmlFor="crossfadeMs" className="text-sm font-medium leading-none">
|
||||
Chunk crossfade
|
||||
</label>
|
||||
<span className="text-sm tabular-nums text-muted-foreground">
|
||||
{crossfadeMs === 0 ? 'Cut' : `${crossfadeMs}ms`}
|
||||
</span>
|
||||
</div>
|
||||
<Slider
|
||||
id="crossfadeMs"
|
||||
value={[crossfadeMs]}
|
||||
onValueChange={([value]) => setCrossfadeMs(value)}
|
||||
min={0}
|
||||
max={200}
|
||||
step={10}
|
||||
aria-label="Chunk crossfade duration"
|
||||
/>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Blends audio between chunks to smooth transitions. Set to 0 for a hard cut.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
@@ -37,6 +37,7 @@ export interface GenerationRequest {
|
||||
engine?: 'qwen' | 'luxtts' | 'chatterbox' | 'chatterbox_turbo';
|
||||
instruct?: string;
|
||||
max_chunk_chars?: number;
|
||||
crossfade_ms?: number;
|
||||
}
|
||||
|
||||
export interface GenerationResponse {
|
||||
|
||||
@@ -33,6 +33,7 @@ export function useGenerationForm(options: UseGenerationFormOptions = {}) {
|
||||
const setAudioWithAutoPlay = usePlayerStore((state) => state.setAudioWithAutoPlay);
|
||||
const setIsGenerating = useGenerationStore((state) => state.setIsGenerating);
|
||||
const maxChunkChars = useServerStore((state) => state.maxChunkChars);
|
||||
const crossfadeMs = useServerStore((state) => state.crossfadeMs);
|
||||
const [downloadingModelName, setDownloadingModelName] = useState<string | null>(null);
|
||||
const [downloadingDisplayName, setDownloadingDisplayName] = useState<string | null>(null);
|
||||
|
||||
@@ -113,6 +114,7 @@ export function useGenerationForm(options: UseGenerationFormOptions = {}) {
|
||||
engine,
|
||||
instruct: isQwen ? data.instruct || undefined : undefined,
|
||||
max_chunk_chars: maxChunkChars,
|
||||
crossfade_ms: crossfadeMs,
|
||||
});
|
||||
|
||||
toast({
|
||||
|
||||
@@ -16,6 +16,9 @@ interface ServerStore {
|
||||
|
||||
maxChunkChars: number;
|
||||
setMaxChunkChars: (value: number) => void;
|
||||
|
||||
crossfadeMs: number;
|
||||
setCrossfadeMs: (value: number) => void;
|
||||
}
|
||||
|
||||
export const useServerStore = create<ServerStore>()(
|
||||
@@ -35,6 +38,9 @@ export const useServerStore = create<ServerStore>()(
|
||||
|
||||
maxChunkChars: 800,
|
||||
setMaxChunkChars: (value) => set({ maxChunkChars: value }),
|
||||
|
||||
crossfadeMs: 50,
|
||||
setCrossfadeMs: (value) => set({ crossfadeMs: value }),
|
||||
}),
|
||||
{
|
||||
name: 'voicebox-server',
|
||||
|
||||
Reference in New Issue
Block a user