clement-pages commited on
Commit
df60b7b
·
1 Parent(s): 4712d9f

update component's frontend

Browse files

Now the component is able to display each sources and corresponding
annotation separately

sourceviewer/frontend/Index.svelte CHANGED
@@ -10,13 +10,13 @@
10
  import InteractiveAudio from "./interactive/InteractiveAudio.svelte";
11
  import { StatusTracker } from "@gradio/statustracker";
12
  import { Block, UploadText } from "@gradio/atoms";
13
- import type { WaveformOptions } from "./shared/types";
14
 
15
  export let elem_id = "";
16
  export let elem_classes: string[] = [];
17
  export let visible = true;
18
  export let interactive: boolean;
19
- export let value: null | FileData = null;
20
  export let sources:
21
  | ["microphone"]
22
  | ["upload"]
@@ -54,11 +54,11 @@
54
  share: ShareData;
55
  }>;
56
 
57
- let old_value: null | FileData = null;
58
 
59
  let active_source: "microphone" | "upload";
60
 
61
- let initial_value: null | FileData = value;
62
 
63
  $: if (value && initial_value === null) {
64
  initial_value = value;
@@ -105,23 +105,10 @@
105
  normalize: true,
106
  minPxPerSec: 20,
107
  mediaControls: waveform_options.show_controls,
108
- sampleRate: waveform_options.sample_rate || 44100
 
109
  };
110
 
111
- const trim_region_settings = {
112
- color: waveform_options.trim_region_color,
113
- drag: true,
114
- resize: true
115
- };
116
-
117
- function set_trim_region_colour(): void {
118
- document.documentElement.style.setProperty(
119
- "--trim-region-color",
120
- trim_region_settings.color || color_accent
121
- );
122
- }
123
-
124
- set_trim_region_colour();
125
 
126
  function handle_error({ detail }: CustomEvent<string>): void {
127
  const [level, status] = detail.includes("Invalid file type")
@@ -160,6 +147,7 @@
160
  {show_share_button}
161
  {value}
162
  {label}
 
163
  {waveform_settings}
164
  {waveform_options}
165
  {editable}
@@ -220,7 +208,6 @@
220
  i18n={gradio.i18n}
221
  {waveform_settings}
222
  {waveform_options}
223
- {trim_region_settings}
224
  >
225
  <UploadText i18n={gradio.i18n} type="audio" />
226
  </InteractiveAudio>
 
10
  import InteractiveAudio from "./interactive/InteractiveAudio.svelte";
11
  import { StatusTracker } from "@gradio/statustracker";
12
  import { Block, UploadText } from "@gradio/atoms";
13
+ import type { WaveformOptions, Segment } from "./shared/types";
14
 
15
  export let elem_id = "";
16
  export let elem_classes: string[] = [];
17
  export let visible = true;
18
  export let interactive: boolean;
19
+ export let value: null | {"segments": Segment[], "sources_file": FileData} = null;
20
  export let sources:
21
  | ["microphone"]
22
  | ["upload"]
 
54
  share: ShareData;
55
  }>;
56
 
57
+ let old_value: null | {"segments": Segment[], "sources_file": FileData} = null;
58
 
59
  let active_source: "microphone" | "upload";
60
 
61
+ let initial_value: null | {"segments": Segment[], "sources_file": FileData} = value;
62
 
63
  $: if (value && initial_value === null) {
64
  initial_value = value;
 
105
  normalize: true,
106
  minPxPerSec: 20,
107
  mediaControls: waveform_options.show_controls,
108
+ sampleRate: waveform_options.sample_rate || 44100,
109
+ splitChannels: true,
110
  };
111
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
112
 
113
  function handle_error({ detail }: CustomEvent<string>): void {
114
  const [level, status] = detail.includes("Invalid file type")
 
147
  {show_share_button}
148
  {value}
149
  {label}
150
+ {root}
151
  {waveform_settings}
152
  {waveform_options}
153
  {editable}
 
208
  i18n={gradio.i18n}
209
  {waveform_settings}
210
  {waveform_options}
 
211
  >
212
  <UploadText i18n={gradio.i18n} type="audio" />
213
  </InteractiveAudio>
sourceviewer/frontend/interactive/InteractiveAudio.svelte CHANGED
@@ -18,7 +18,7 @@
18
  import { SelectSource } from "@gradio/atoms";
19
  import type { WaveformOptions } from "../shared/types";
20
 
21
- export let value: null | FileData = null;
22
  export let label: string;
23
  export let root: string;
24
  export let show_label = true;
@@ -32,7 +32,6 @@
32
  export let streaming = false;
33
  export let i18n: I18nFormatter;
34
  export let waveform_settings: Record<string, any>;
35
- export let trim_region_settings = {};
36
  export let waveform_options: WaveformOptions = {};
37
  export let dragging: boolean;
38
  export let active_source: "microphone" | "upload";
@@ -74,7 +73,7 @@
74
  }
75
 
76
  const dispatch = createEventDispatcher<{
77
- change: FileData | null;
78
  stream: FileData;
79
  edit: never;
80
  play: never;
@@ -96,7 +95,7 @@
96
  ): Promise<void> => {
97
  let _audio_blob = new File(blobs, "audio.wav");
98
  const val = await prepare_files([_audio_blob], event === "stream");
99
- value = (
100
  (await upload(val, root, undefined, upload_fn))?.filter(
101
  Boolean
102
  ) as FileData[]
@@ -193,8 +192,9 @@
193
  }
194
 
195
  function handle_load({ detail }: { detail: FileData }): void {
196
- value = detail;
197
- dispatch("change", detail);
 
198
  dispatch("upload", detail);
199
  }
200
 
@@ -264,7 +264,7 @@
264
  {i18n}
265
  on:clear={clear}
266
  on:edit={() => (mode = "edit")}
267
- download={show_download_button ? value.url : null}
268
  absolute={true}
269
  />
270
 
@@ -272,11 +272,11 @@
272
  bind:mode
273
  {value}
274
  {label}
 
275
  {i18n}
276
  {dispatch_blob}
277
  {waveform_settings}
278
  {waveform_options}
279
- {trim_region_settings}
280
  {handle_reset_value}
281
  {editable}
282
  interactive
 
18
  import { SelectSource } from "@gradio/atoms";
19
  import type { WaveformOptions } from "../shared/types";
20
 
21
+ export let value: null | {"segments": Segment[], "sources_file": FileData} = null;
22
  export let label: string;
23
  export let root: string;
24
  export let show_label = true;
 
32
  export let streaming = false;
33
  export let i18n: I18nFormatter;
34
  export let waveform_settings: Record<string, any>;
 
35
  export let waveform_options: WaveformOptions = {};
36
  export let dragging: boolean;
37
  export let active_source: "microphone" | "upload";
 
73
  }
74
 
75
  const dispatch = createEventDispatcher<{
76
+ change: typeof value;
77
  stream: FileData;
78
  edit: never;
79
  play: never;
 
95
  ): Promise<void> => {
96
  let _audio_blob = new File(blobs, "audio.wav");
97
  const val = await prepare_files([_audio_blob], event === "stream");
98
+ value.sources_file = (
99
  (await upload(val, root, undefined, upload_fn))?.filter(
100
  Boolean
101
  ) as FileData[]
 
192
  }
193
 
194
  function handle_load({ detail }: { detail: FileData }): void {
195
+ value = {"segments": [], "sources_file": null}
196
+ value.sources_file = detail;
197
+ dispatch("change", value);
198
  dispatch("upload", detail);
199
  }
200
 
 
264
  {i18n}
265
  on:clear={clear}
266
  on:edit={() => (mode = "edit")}
267
+ download={show_download_button ? value.sources_file.url : null}
268
  absolute={true}
269
  />
270
 
 
272
  bind:mode
273
  {value}
274
  {label}
275
+ {root}
276
  {i18n}
277
  {dispatch_blob}
278
  {waveform_settings}
279
  {waveform_options}
 
280
  {handle_reset_value}
281
  {editable}
282
  interactive
sourceviewer/frontend/package-lock.json CHANGED
@@ -22,7 +22,7 @@
22
  "extendable-media-recorder-wav-encoder": "^7.0.76",
23
  "resize-observer-polyfill": "^1.5.1",
24
  "svelte-range-slider-pips": "^2.0.1",
25
- "wavesurfer.js": "^7.4.2"
26
  }
27
  },
28
  "node_modules/@ampproject/remapping": {
@@ -1258,9 +1258,10 @@
1258
  "integrity": "sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ=="
1259
  },
1260
  "node_modules/wavesurfer.js": {
1261
- "version": "7.8.8",
1262
- "resolved": "https://registry.npmjs.org/wavesurfer.js/-/wavesurfer.js-7.8.8.tgz",
1263
- "integrity": "sha512-FNiJ6RCAu4TijRcwdaqlN19+Y+Hhqb7Nfo2P4LudzhNnQRMKvF3QmXd9+KHlQZrSjexeK3WbY4COsxgGJkxMag=="
 
1264
  },
1265
  "node_modules/worker-factory": {
1266
  "version": "7.0.34",
 
22
  "extendable-media-recorder-wav-encoder": "^7.0.76",
23
  "resize-observer-polyfill": "^1.5.1",
24
  "svelte-range-slider-pips": "^2.0.1",
25
+ "wavesurfer.js": "^7.8.9"
26
  }
27
  },
28
  "node_modules/@ampproject/remapping": {
 
1258
  "integrity": "sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ=="
1259
  },
1260
  "node_modules/wavesurfer.js": {
1261
+ "version": "7.8.9",
1262
+ "resolved": "https://registry.npmjs.org/wavesurfer.js/-/wavesurfer.js-7.8.9.tgz",
1263
+ "integrity": "sha512-d7jDSrzNp3UErXWEKFlIYRdvzaMlxCoM6Or4qR8uURFp9smcxLXS81uatcs6aPX1OSJgEyyBuffMR5Io3Ft2FQ==",
1264
+ "license": "BSD-3-Clause"
1265
  },
1266
  "node_modules/worker-factory": {
1267
  "version": "7.0.34",
sourceviewer/frontend/package.json CHANGED
@@ -15,12 +15,12 @@
15
  "@gradio/upload": "0.8.5",
16
  "@gradio/utils": "0.3.2",
17
  "@gradio/wasm": "0.10.0",
 
18
  "extendable-media-recorder": "^9.0.0",
19
  "extendable-media-recorder-wav-encoder": "^7.0.76",
20
  "resize-observer-polyfill": "^1.5.1",
21
  "svelte-range-slider-pips": "^2.0.1",
22
- "wavesurfer.js": "^7.4.2",
23
- "@types/wavesurfer.js": "^6.0.10"
24
  },
25
  "main_changeset": true,
26
  "main": "index.ts",
@@ -30,4 +30,4 @@
30
  "./shared": "./shared/index.ts",
31
  "./package.json": "./package.json"
32
  }
33
- }
 
15
  "@gradio/upload": "0.8.5",
16
  "@gradio/utils": "0.3.2",
17
  "@gradio/wasm": "0.10.0",
18
+ "@types/wavesurfer.js": "^6.0.10",
19
  "extendable-media-recorder": "^9.0.0",
20
  "extendable-media-recorder-wav-encoder": "^7.0.76",
21
  "resize-observer-polyfill": "^1.5.1",
22
  "svelte-range-slider-pips": "^2.0.1",
23
+ "wavesurfer.js": "^7.8.9"
 
24
  },
25
  "main_changeset": true,
26
  "main": "index.ts",
 
30
  "./shared": "./shared/index.ts",
31
  "./package.json": "./package.json"
32
  }
33
+ }
sourceviewer/frontend/player/AudioPlayer.svelte CHANGED
@@ -3,17 +3,19 @@
3
  import { Music } from "@gradio/icons";
4
  import { format_time, type I18nFormatter } from "@gradio/utils";
5
  import WaveSurfer from "wavesurfer.js";
 
6
  import { skip_audio, process_audio } from "../shared/utils";
7
  import WaveformControls from "../shared/WaveformControls.svelte";
8
  import { Empty } from "@gradio/atoms";
9
  import { resolve_wasm_src } from "@gradio/wasm/svelte";
10
  import type { FileData } from "@gradio/client";
11
- import type { WaveformOptions } from "../shared/types";
12
  import { createEventDispatcher } from "svelte";
13
 
14
- export let value: null | FileData = null;
15
- $: url = value?.url;
16
  export let label: string;
 
17
  export let i18n: I18nFormatter;
18
  export let dispatch_blob: (
19
  blobs: Uint8Array[] | Blob[],
@@ -21,7 +23,6 @@
21
  ) => Promise<void> = () => Promise.resolve();
22
  export let interactive = false;
23
  export let editable = true;
24
- export let trim_region_settings = {};
25
  export let waveform_settings: Record<string, any>;
26
  export let waveform_options: WaveformOptions;
27
  export let mode = "";
@@ -29,12 +30,15 @@
29
 
30
  let container: HTMLDivElement;
31
  let waveform: WaveSurfer | undefined;
 
32
  let playing = false;
33
 
34
  let timeRef: HTMLTimeElement;
35
  let durationRef: HTMLTimeElement;
36
  let audio_duration: number;
37
 
 
 
38
  let trimDuration = 0;
39
 
40
  let show_volume_slider = false;
@@ -52,11 +56,7 @@
52
  container: container,
53
  ...waveform_settings
54
  });
55
- resolve_wasm_src(value?.url).then((resolved_src) => {
56
- if (resolved_src && waveform) {
57
- return waveform.load(resolved_src);
58
- }
59
- });
60
  };
61
 
62
  $: if (container !== undefined) {
@@ -69,6 +69,23 @@
69
  $: waveform?.on("decode", (duration: any) => {
70
  audio_duration = duration;
71
  durationRef && (durationRef.textContent = format_time(duration));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
  });
73
 
74
  $: waveform?.on(
@@ -120,7 +137,7 @@
120
 
121
  async function load_audio(data: string): Promise<void> {
122
  await resolve_wasm_src(data).then((resolved_src) => {
123
- if (!resolved_src || value?.is_stream) return;
124
  return waveform?.load(resolved_src);
125
  });
126
  }
@@ -143,10 +160,10 @@
143
  <Empty size="small">
144
  <Music />
145
  </Empty>
146
- {:else if value.is_stream}
147
  <audio
148
  class="standard-player"
149
- src={value.url}
150
  controls
151
  autoplay={waveform_settings.autoplay}
152
  />
@@ -171,20 +188,17 @@
171
 
172
  {#if waveform}
173
  <WaveformControls
174
- {container}
175
  {waveform}
176
  {playing}
177
  {audio_duration}
178
  {i18n}
179
  {interactive}
180
- {handle_trim_audio}
181
  bind:mode
182
  bind:trimDuration
183
  bind:show_volume_slider
184
  show_redo={interactive}
185
  {handle_reset_value}
186
  {waveform_options}
187
- {trim_region_settings}
188
  {editable}
189
  />
190
  {/if}
 
3
  import { Music } from "@gradio/icons";
4
  import { format_time, type I18nFormatter } from "@gradio/utils";
5
  import WaveSurfer from "wavesurfer.js";
6
+ import RegionsPlugin, {type Region} from "wavesurfer.js/dist/plugins/regions";
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[],
 
23
  ) => Promise<void> = () => Promise.resolve();
24
  export let interactive = false;
25
  export let editable = true;
 
26
  export let waveform_settings: Record<string, any>;
27
  export let waveform_options: WaveformOptions;
28
  export let mode = "";
 
30
 
31
  let container: HTMLDivElement;
32
  let waveform: WaveSurfer | undefined;
33
+ let wsRegion: RegionsPlugin | undefined;
34
  let playing = false;
35
 
36
  let timeRef: HTMLTimeElement;
37
  let durationRef: HTMLTimeElement;
38
  let audio_duration: number;
39
 
40
+ let colors: string[] = ["red", "green", "blue", "yellow", "magenta", "cyan"];
41
+
42
  let trimDuration = 0;
43
 
44
  let show_volume_slider = false;
 
56
  container: container,
57
  ...waveform_settings
58
  });
59
+ waveform.load(root + `/file=${value.sources_file.path}`)
 
 
 
 
60
  };
61
 
62
  $: if (container !== undefined) {
 
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 => {
76
+ const region = wsRegion.addRegion({
77
+ start: segment.start,
78
+ end: segment.end,
79
+ channelIdx: segment.channel,
80
+ drag: false,
81
+ resize: false,
82
+ color: colors[segment.channel % colors.length],
83
+ });
84
+ console.log(region.color)
85
+ const regionHeight = 100 / waveform.getDecodedData().numberOfChannels;
86
+ region.element.style.cssText += `height: ${regionHeight}% !important;`
87
+ });
88
+ }
89
  });
90
 
91
  $: waveform?.on(
 
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
  }
 
160
  <Empty size="small">
161
  <Music />
162
  </Empty>
163
+ {:else if value.sources_file.is_stream}
164
  <audio
165
  class="standard-player"
166
+ src={value.sources_file.url}
167
  controls
168
  autoplay={waveform_settings.autoplay}
169
  />
 
188
 
189
  {#if waveform}
190
  <WaveformControls
 
191
  {waveform}
192
  {playing}
193
  {audio_duration}
194
  {i18n}
195
  {interactive}
 
196
  bind:mode
197
  bind:trimDuration
198
  bind:show_volume_slider
199
  show_redo={interactive}
200
  {handle_reset_value}
201
  {waveform_options}
 
202
  {editable}
203
  />
204
  {/if}
sourceviewer/frontend/shared/WaveformControls.svelte CHANGED
@@ -16,12 +16,9 @@
16
  export let playing: boolean;
17
  export let show_redo = false;
18
  export let interactive = false;
19
- export let handle_trim_audio: (start: number, end: number) => void;
20
  export let mode = "";
21
- export let container: HTMLDivElement;
22
  export let handle_reset_value: () => void;
23
  export let waveform_options: WaveformOptions = {};
24
- export let trim_region_settings: WaveformOptions = {};
25
  export let show_volume_slider = false;
26
  export let editable = true;
27
 
@@ -30,94 +27,10 @@
30
  let playbackSpeeds = [0.5, 1, 1.5, 2];
31
  let playbackSpeed = playbackSpeeds[1];
32
 
33
- let trimRegion: RegionsPlugin;
34
  let activeRegion: Region | null = null;
35
 
36
- let leftRegionHandle: HTMLDivElement | null;
37
- let rightRegionHandle: HTMLDivElement | null;
38
- let activeHandle = "";
39
-
40
  let currentVolume = 1;
41
 
42
- $: trimRegion = waveform.registerPlugin(RegionsPlugin.create());
43
-
44
- $: trimRegion?.on("region-out", (region) => {
45
- region.play();
46
- });
47
-
48
- $: trimRegion?.on("region-updated", (region) => {
49
- trimDuration = region.end - region.start;
50
- });
51
-
52
- $: trimRegion?.on("region-clicked", (region, e) => {
53
- e.stopPropagation(); // prevent triggering a click on the waveform
54
- activeRegion = region;
55
- region.play();
56
- });
57
-
58
- const addTrimRegion = (): void => {
59
- activeRegion = trimRegion.addRegion({
60
- start: audio_duration / 4,
61
- end: audio_duration / 2,
62
- ...trim_region_settings
63
- });
64
-
65
- trimDuration = activeRegion.end - activeRegion.start;
66
- };
67
-
68
- $: if (activeRegion) {
69
- const shadowRoot = container.children[0]!.shadowRoot!;
70
-
71
- rightRegionHandle = shadowRoot.querySelector('[data-resize="right"]');
72
- leftRegionHandle = shadowRoot.querySelector('[data-resize="left"]');
73
-
74
- if (leftRegionHandle && rightRegionHandle) {
75
- leftRegionHandle.setAttribute("role", "button");
76
- rightRegionHandle.setAttribute("role", "button");
77
- leftRegionHandle?.setAttribute("aria-label", "Drag to adjust start time");
78
- rightRegionHandle?.setAttribute("aria-label", "Drag to adjust end time");
79
- leftRegionHandle?.setAttribute("tabindex", "0");
80
- rightRegionHandle?.setAttribute("tabindex", "0");
81
-
82
- leftRegionHandle.addEventListener("focus", () => {
83
- if (trimRegion) activeHandle = "left";
84
- });
85
-
86
- rightRegionHandle.addEventListener("focus", () => {
87
- if (trimRegion) activeHandle = "right";
88
- });
89
- }
90
- }
91
-
92
- const trimAudio = (): void => {
93
- if (waveform && trimRegion) {
94
- if (activeRegion) {
95
- const start = activeRegion.start;
96
- const end = activeRegion.end;
97
- handle_trim_audio(start, end);
98
- mode = "";
99
- activeRegion = null;
100
- }
101
- }
102
- };
103
-
104
- const clearRegions = (): void => {
105
- trimRegion?.getRegions().forEach((region) => {
106
- region.remove();
107
- });
108
- trimRegion?.clearRegions();
109
- };
110
-
111
- const toggleTrimmingMode = (): void => {
112
- clearRegions();
113
- if (mode === "edit") {
114
- mode = "";
115
- } else {
116
- mode = "edit";
117
- addTrimRegion();
118
- }
119
- };
120
-
121
  const adjustRegionHandles = (handle: string, key: string): void => {
122
  let newStart;
123
  let newEnd;
@@ -149,14 +62,6 @@
149
  trimDuration = activeRegion.end - activeRegion.start;
150
  };
151
 
152
- $: trimRegion &&
153
- window.addEventListener("keydown", (e) => {
154
- if (e.key === "ArrowLeft") {
155
- adjustRegionHandles(activeHandle, "ArrowLeft");
156
- } else if (e.key === "ArrowRight") {
157
- adjustRegionHandles(activeHandle, "ArrowRight");
158
- }
159
- });
160
  </script>
161
 
162
  <div class="controls" data-testid="waveform-controls">
@@ -246,27 +151,12 @@
246
  aria-label="Reset audio"
247
  on:click={() => {
248
  handle_reset_value();
249
- clearRegions();
250
  mode = "";
251
  }}
252
  >
253
  <Undo />
254
  </button>
255
  {/if}
256
-
257
- {#if mode === ""}
258
- <button
259
- class="action icon"
260
- aria-label="Trim audio to selection"
261
- on:click={toggleTrimmingMode}
262
- >
263
- <Trim />
264
- </button>
265
- {:else}
266
- <button class="text-button" on:click={trimAudio}>Trim</button>
267
- <button class="text-button" on:click={toggleTrimmingMode}>Cancel</button
268
- >
269
- {/if}
270
  {/if}
271
  </div>
272
  </div>
@@ -278,24 +168,6 @@
278
  align-items: center;
279
  grid-area: editing;
280
  }
281
- .text-button {
282
- border: 1px solid var(--neutral-400);
283
- border-radius: var(--radius-sm);
284
- font-weight: 300;
285
- font-size: var(--size-3);
286
- text-align: center;
287
- color: var(--neutral-400);
288
- height: var(--size-5);
289
- font-weight: bold;
290
- padding: 0 5px;
291
- margin-left: 5px;
292
- }
293
-
294
- .text-button:hover,
295
- .text-button:focus {
296
- color: var(--color-accent);
297
- border-color: var(--color-accent);
298
- }
299
 
300
  .controls {
301
  display: grid;
 
16
  export let playing: boolean;
17
  export let show_redo = false;
18
  export let interactive = false;
 
19
  export let mode = "";
 
20
  export let handle_reset_value: () => void;
21
  export let waveform_options: WaveformOptions = {};
 
22
  export let show_volume_slider = false;
23
  export let editable = true;
24
 
 
27
  let playbackSpeeds = [0.5, 1, 1.5, 2];
28
  let playbackSpeed = playbackSpeeds[1];
29
 
 
30
  let activeRegion: Region | null = null;
31
 
 
 
 
 
32
  let currentVolume = 1;
33
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
  const adjustRegionHandles = (handle: string, key: string): void => {
35
  let newStart;
36
  let newEnd;
 
62
  trimDuration = activeRegion.end - activeRegion.start;
63
  };
64
 
 
 
 
 
 
 
 
 
65
  </script>
66
 
67
  <div class="controls" data-testid="waveform-controls">
 
151
  aria-label="Reset audio"
152
  on:click={() => {
153
  handle_reset_value();
 
154
  mode = "";
155
  }}
156
  >
157
  <Undo />
158
  </button>
159
  {/if}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
160
  {/if}
161
  </div>
162
  </div>
 
168
  align-items: center;
169
  grid-area: editing;
170
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
171
 
172
  .controls {
173
  display: grid;
sourceviewer/frontend/shared/WaveformRecordControls.svelte CHANGED
@@ -245,7 +245,6 @@
245
 
246
  :global(::part(region)) {
247
  border-radius: var(--radius-md);
248
- height: 98% !important;
249
  border: 1px solid var(--trim-region-color);
250
  background-color: unset;
251
  border-width: 1px 3px;
@@ -258,7 +257,6 @@
258
  left: 0;
259
  width: 100%;
260
  height: 100%;
261
- background: var(--trim-region-color);
262
  opacity: 0.2;
263
  border-radius: var(--radius-md);
264
  }
 
245
 
246
  :global(::part(region)) {
247
  border-radius: var(--radius-md);
 
248
  border: 1px solid var(--trim-region-color);
249
  background-color: unset;
250
  border-width: 1px 3px;
 
257
  left: 0;
258
  width: 100%;
259
  height: 100%;
 
260
  opacity: 0.2;
261
  border-radius: var(--radius-md);
262
  }
sourceviewer/frontend/shared/types.ts CHANGED
@@ -7,3 +7,9 @@ export type WaveformOptions = {
7
  show_recording_waveform?: boolean;
8
  sample_rate?: number;
9
  };
 
 
 
 
 
 
 
7
  show_recording_waveform?: boolean;
8
  sample_rate?: number;
9
  };
10
+
11
+ export type Segment = {
12
+ start: number;
13
+ end: number;
14
+ channel: number;
15
+ }
sourceviewer/frontend/static/StaticAudio.svelte CHANGED
@@ -8,10 +8,11 @@
8
  import { createEventDispatcher } from "svelte";
9
  import type { FileData } from "@gradio/client";
10
  import { DownloadLink } from "@gradio/wasm/svelte";
11
- import type { WaveformOptions } from "../shared/types";
12
 
13
- export let value: null | FileData = null;
14
  export let label: string;
 
15
  export let show_label = true;
16
  export let show_download_button = true;
17
  export let show_share_button = false;
@@ -21,7 +22,7 @@
21
  export let editable = true;
22
 
23
  const dispatch = createEventDispatcher<{
24
- change: FileData;
25
  play: undefined;
26
  pause: undefined;
27
  end: undefined;
@@ -41,7 +42,7 @@
41
  {#if value !== null}
42
  <div class="icon-buttons">
43
  {#if show_download_button}
44
- <DownloadLink href={value.url} download={value.orig_name || value.path}>
45
  <IconButton Icon={Download} label={i18n("common.download")} />
46
  </DownloadLink>
47
  {/if}
@@ -63,6 +64,7 @@
63
  <AudioPlayer
64
  {value}
65
  {label}
 
66
  {i18n}
67
  {waveform_settings}
68
  {waveform_options}
 
8
  import { createEventDispatcher } from "svelte";
9
  import type { FileData } from "@gradio/client";
10
  import { DownloadLink } from "@gradio/wasm/svelte";
11
+ import type { WaveformOptions, Segment } from "../shared/types";
12
 
13
+ export let value: null | {"segments": Segment[], "sources_file": FileData} = null;
14
  export let label: string;
15
+ export let root: string;
16
  export let show_label = true;
17
  export let show_download_button = true;
18
  export let show_share_button = false;
 
22
  export let editable = true;
23
 
24
  const dispatch = createEventDispatcher<{
25
+ change: typeof value;
26
  play: undefined;
27
  pause: undefined;
28
  end: undefined;
 
42
  {#if value !== null}
43
  <div class="icon-buttons">
44
  {#if show_download_button}
45
+ <DownloadLink href={value.sources_file.url} download={value.sources_file.orig_name || value.sources_file.path}>
46
  <IconButton Icon={Download} label={i18n("common.download")} />
47
  </DownloadLink>
48
  {/if}
 
64
  <AudioPlayer
65
  {value}
66
  {label}
67
+ {root}
68
  {i18n}
69
  {waveform_settings}
70
  {waveform_options}