Commit
·
7615d1a
1
Parent(s):
df60b7b
add source selection
Browse files
sourceviewer/frontend/player/AudioPlayer.svelte
CHANGED
@@ -7,20 +7,14 @@
|
|
7 |
import { skip_audio, process_audio } from "../shared/utils";
|
8 |
import WaveformControls from "../shared/WaveformControls.svelte";
|
9 |
import { Empty } from "@gradio/atoms";
|
10 |
-
import { resolve_wasm_src } from "@gradio/wasm/svelte";
|
11 |
import type { FileData } from "@gradio/client";
|
12 |
import type { WaveformOptions, Segment } from "../shared/types";
|
13 |
import { createEventDispatcher } from "svelte";
|
14 |
|
15 |
export let value: null | {"segments": Segment[], "sources_file": FileData}= null;
|
16 |
-
$: url = value?.sources_file.url;
|
17 |
export let label: string;
|
18 |
export let root: string;
|
19 |
export let i18n: I18nFormatter;
|
20 |
-
export let dispatch_blob: (
|
21 |
-
blobs: Uint8Array[] | Blob[],
|
22 |
-
event: "stream" | "change" | "stop_recording"
|
23 |
-
) => Promise<void> = () => Promise.resolve();
|
24 |
export let interactive = false;
|
25 |
export let editable = true;
|
26 |
export let waveform_settings: Record<string, any>;
|
@@ -39,6 +33,10 @@
|
|
39 |
|
40 |
let colors: string[] = ["red", "green", "blue", "yellow", "magenta", "cyan"];
|
41 |
|
|
|
|
|
|
|
|
|
42 |
let trimDuration = 0;
|
43 |
|
44 |
let show_volume_slider = false;
|
@@ -52,11 +50,16 @@
|
|
52 |
}>();
|
53 |
|
54 |
const create_waveform = (): void => {
|
|
|
|
|
|
|
|
|
|
|
55 |
waveform = WaveSurfer.create({
|
56 |
container: container,
|
|
|
57 |
...waveform_settings
|
58 |
});
|
59 |
-
waveform.load(root + `/file=${value.sources_file.path}`)
|
60 |
};
|
61 |
|
62 |
$: if (container !== undefined) {
|
@@ -67,9 +70,17 @@
|
|
67 |
}
|
68 |
|
69 |
$: waveform?.on("decode", (duration: any) => {
|
|
|
|
|
70 |
audio_duration = duration;
|
71 |
durationRef && (durationRef.textContent = format_time(duration));
|
|
|
|
|
72 |
|
|
|
|
|
|
|
|
|
73 |
if(!wsRegion){
|
74 |
wsRegion = waveform.registerPlugin(RegionsPlugin.create())
|
75 |
value.segments.forEach(segment => {
|
@@ -81,8 +92,8 @@
|
|
81 |
resize: false,
|
82 |
color: colors[segment.channel % colors.length],
|
83 |
});
|
84 |
-
|
85 |
-
const regionHeight = 100 /
|
86 |
region.element.style.cssText += `height: ${regionHeight}% !important;`
|
87 |
});
|
88 |
}
|
@@ -115,35 +126,6 @@
|
|
115 |
dispatch("play");
|
116 |
});
|
117 |
|
118 |
-
const handle_trim_audio = async (
|
119 |
-
start: number,
|
120 |
-
end: number
|
121 |
-
): Promise<void> => {
|
122 |
-
mode = "";
|
123 |
-
const decodedData = waveform?.getDecodedData();
|
124 |
-
if (decodedData)
|
125 |
-
await process_audio(
|
126 |
-
decodedData,
|
127 |
-
start,
|
128 |
-
end,
|
129 |
-
waveform_settings.sampleRate
|
130 |
-
).then(async (trimmedBlob: Uint8Array) => {
|
131 |
-
await dispatch_blob([trimmedBlob], "change");
|
132 |
-
waveform?.destroy();
|
133 |
-
container.innerHTML = "";
|
134 |
-
});
|
135 |
-
dispatch("edit");
|
136 |
-
};
|
137 |
-
|
138 |
-
async function load_audio(data: string): Promise<void> {
|
139 |
-
await resolve_wasm_src(data).then((resolved_src) => {
|
140 |
-
if (!resolved_src || value?.sources_file.is_stream) return;
|
141 |
-
return waveform?.load(resolved_src);
|
142 |
-
});
|
143 |
-
}
|
144 |
-
|
145 |
-
$: url && load_audio(url);
|
146 |
-
|
147 |
onMount(() => {
|
148 |
window.addEventListener("keydown", (e) => {
|
149 |
if (!waveform || show_volume_slider) return;
|
@@ -186,6 +168,23 @@
|
|
186 |
</div>
|
187 |
</div>
|
188 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
189 |
{#if waveform}
|
190 |
<WaveformControls
|
191 |
{waveform}
|
|
|
7 |
import { skip_audio, process_audio } from "../shared/utils";
|
8 |
import WaveformControls from "../shared/WaveformControls.svelte";
|
9 |
import { Empty } from "@gradio/atoms";
|
|
|
10 |
import type { FileData } from "@gradio/client";
|
11 |
import type { WaveformOptions, Segment } from "../shared/types";
|
12 |
import { createEventDispatcher } from "svelte";
|
13 |
|
14 |
export let value: null | {"segments": Segment[], "sources_file": FileData}= null;
|
|
|
15 |
export let label: string;
|
16 |
export let root: string;
|
17 |
export let i18n: I18nFormatter;
|
|
|
|
|
|
|
|
|
18 |
export let interactive = false;
|
19 |
export let editable = true;
|
20 |
export let waveform_settings: Record<string, any>;
|
|
|
33 |
|
34 |
let colors: string[] = ["red", "green", "blue", "yellow", "magenta", "cyan"];
|
35 |
|
36 |
+
let audioDecoded: boolean = false;
|
37 |
+
let audioContext: AudioContext | undefined;
|
38 |
+
let mediaNode: MediaElementAudioSourceNode | undefined;
|
39 |
+
let splitter: ChannelSplitterNode | undefined;
|
40 |
let trimDuration = 0;
|
41 |
|
42 |
let show_volume_slider = false;
|
|
|
50 |
}>();
|
51 |
|
52 |
const create_waveform = (): void => {
|
53 |
+
const audio = new Audio(root + `/file=${value.sources_file.path}`)
|
54 |
+
audio.crossOrigin = "anonymous"
|
55 |
+
|
56 |
+
audioContext = new AudioContext();
|
57 |
+
|
58 |
waveform = WaveSurfer.create({
|
59 |
container: container,
|
60 |
+
media: audio,
|
61 |
...waveform_settings
|
62 |
});
|
|
|
63 |
};
|
64 |
|
65 |
$: if (container !== undefined) {
|
|
|
70 |
}
|
71 |
|
72 |
$: waveform?.on("decode", (duration: any) => {
|
73 |
+
audioDecoded = true;
|
74 |
+
const numChannels = waveform.getDecodedData().numberOfChannels;
|
75 |
audio_duration = duration;
|
76 |
durationRef && (durationRef.textContent = format_time(duration));
|
77 |
+
|
78 |
+
mediaNode = audioContext.createMediaElementSource(waveform.getMediaElement() );
|
79 |
|
80 |
+
splitter = audioContext.createChannelSplitter(numChannels);
|
81 |
+
mediaNode.connect(splitter);
|
82 |
+
|
83 |
+
// add diarization annotation on each source:
|
84 |
if(!wsRegion){
|
85 |
wsRegion = waveform.registerPlugin(RegionsPlugin.create())
|
86 |
value.segments.forEach(segment => {
|
|
|
92 |
resize: false,
|
93 |
color: colors[segment.channel % colors.length],
|
94 |
});
|
95 |
+
|
96 |
+
const regionHeight = 100 / numChannels;
|
97 |
region.element.style.cssText += `height: ${regionHeight}% !important;`
|
98 |
});
|
99 |
}
|
|
|
126 |
dispatch("play");
|
127 |
});
|
128 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
129 |
onMount(() => {
|
130 |
window.addEventListener("keydown", (e) => {
|
131 |
if (!waveform || show_volume_slider) return;
|
|
|
168 |
</div>
|
169 |
</div>
|
170 |
|
171 |
+
{#if audioDecoded}
|
172 |
+
{#each [...Array(waveform.getDecodedData().numberOfChannels).keys()] as channelIdx}
|
173 |
+
<label>
|
174 |
+
<input
|
175 |
+
type="radio"
|
176 |
+
name="channels"
|
177 |
+
value={`${channelIdx}`}
|
178 |
+
on:change={(ev) => {
|
179 |
+
splitter.disconnect()
|
180 |
+
splitter.connect(audioContext.destination, Number(ev.target.value), 0);
|
181 |
+
}}
|
182 |
+
/>
|
183 |
+
{channelIdx}
|
184 |
+
</label>
|
185 |
+
{/each}
|
186 |
+
{/if}
|
187 |
+
|
188 |
{#if waveform}
|
189 |
<WaveformControls
|
190 |
{waveform}
|