Skip to content

minor bug fix in sample pages #721

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Jul 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
393 changes: 222 additions & 171 deletions frontend/packages/core/components/Audio.tsx

Large diffs are not rendered by default.

7 changes: 6 additions & 1 deletion frontend/packages/core/components/Chart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,12 @@ const Chart: FunctionComponent<ChartProps & WithStyled> = ({cid, width, height,
}, [toggleMaximze]);

return (
<Div maximized={maximized} width={width} height={height} className={className}>
<Div
maximized={maximized}
width={width}
height={height}
className={`${maximized ? 'maximized' : ''} ${className ?? ''}`}
>
{children}
</Div>
);
Expand Down
4 changes: 4 additions & 0 deletions frontend/packages/core/components/ChartPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ const Wrapper = styled.div`
margin: 0 ${rem(20)} ${rem(20)} 0;
flex-shrink: 0;
flex-grow: 0;

&.maximized {
margin-right: 0;
}
}
`;

Expand Down
2 changes: 0 additions & 2 deletions frontend/packages/core/components/RangeSlider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ const Wrapper = styled.div<{disabled?: boolean}>`

&__track {
cursor: ${props => (props.disabled ? 'not-allowed' : 'pointer')};
${transitionProps('width', {duration: '30ms'})}

&--background {
${size(railHeight, '100%')}
Expand All @@ -67,7 +66,6 @@ const Wrapper = styled.div<{disabled?: boolean}>`
&__slider-container {
top: -${half(`${thumbSize} - ${railHeight}`)};
margin-left: -${half(thumbSize)};
${transitionProps('left', {duration: '30ms'})}
}

&__slider {
Expand Down
21 changes: 15 additions & 6 deletions frontend/packages/core/components/SamplePage/AudioChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,24 @@ import React, {FunctionComponent, useCallback, useState} from 'react';
import SampleChart, {SampleChartBaseProps} from '~/components/SamplePage/SampleChart';

import {format} from 'd3-format';
import {size} from '~/utils/style';
import styled from 'styled-components';
import {useTranslation} from '~/utils/i18n';

const formatter = format('.5~s');

const StyledAudio = styled(Audio)`
${size('100%')}
width: 100%;
flex-shrink: 1;
align-self: stretch;
`;

const cache = 5 * 60 * 1000;

type AudioChartProps = SampleChartBaseProps;
type AudioChartProps = {
audioContext?: AudioContext;
} & SampleChartBaseProps;

const AudioChart: FunctionComponent<AudioChartProps> = ({...props}) => {
const AudioChart: FunctionComponent<AudioChartProps> = ({audioContext, ...props}) => {
const {t} = useTranslation(['sample', 'common']);

const [sampleRate, setSampleRate] = useState<string>('--Hz');
Expand All @@ -31,9 +33,16 @@ const AudioChart: FunctionComponent<AudioChartProps> = ({...props}) => {

const content = useCallback(
(ref: React.RefObject<AudioRef>, src: string) => (
<StyledAudio src={src} cache={cache} onLoading={onLoading} onLoad={onLoad} ref={ref} />
<StyledAudio
audioContext={audioContext}
src={src}
cache={cache}
onLoading={onLoading}
onLoad={onLoad}
ref={ref}
/>
),
[onLoading, onLoad]
[onLoading, onLoad, audioContext]
);

return (
Expand Down
2 changes: 2 additions & 0 deletions frontend/packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
"react-dom": "16.13.1",
"react-input-range": "1.3.0",
"react-is": "16.13.1",
"react-rangeslider": "2.2.0",
"react-spinners": "0.9.0",
"react-toastify": "6.0.8",
"save-svg-as-png": "1.4.17",
Expand All @@ -77,6 +78,7 @@
"@types/nprogress": "0.2.0",
"@types/react": "16.9.43",
"@types/react-dom": "16.9.8",
"@types/react-rangeslider": "2.2.3",
"@types/styled-components": "5.1.1",
"@visualdl/mock": "2.0.0-beta.49",
"babel-plugin-emotion": "10.0.33",
Expand Down
17 changes: 15 additions & 2 deletions frontend/packages/core/pages/sample/audio.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import ChartPage, {WithChart} from '~/components/ChartPage';
import {NextI18NextPage, useTranslation} from '~/utils/i18n';
import React, {useCallback, useMemo, useState} from 'react';
import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
import useTagFilter, {ungroup} from '~/hooks/useTagFilter';

import AudioChart from '~/components/SamplePage/AudioChart';
Expand All @@ -20,6 +20,19 @@ const chartSize = {
const Audio: NextI18NextPage = () => {
const {t} = useTranslation(['sample', 'common']);

const audioContext = useRef<AudioContext>();
useEffect(() => {
if (process.browser) {
// safari only has webkitAudioContext
const AudioContext = globalThis.AudioContext || globalThis.webkitAudioContext;
audioContext.current = new AudioContext();

return () => {
audioContext.current?.close();
};
}
}, []);

const [running, setRunning] = useState(true);

const {runs, tags, selectedRuns, onChangeRuns, loadingRuns, loadingTags} = useTagFilter('audio', running);
Expand All @@ -41,7 +54,7 @@ const Audio: NextI18NextPage = () => {
);

const withChart = useCallback<WithChart<typeof ungroupedSelectedTags[number]>>(
({run, label}) => <AudioChart run={run} tag={label} running={running} />,
({run, label}) => <AudioChart audioContext={audioContext.current} run={run} tag={label} running={running} />,
[running]
);

Expand Down
2 changes: 1 addition & 1 deletion frontend/packages/core/public/locales/zh/common.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"audio": "语音",
"audio": "音频",
"cancel": "取消",
"close": "关闭",
"colon": ":",
Expand Down
4 changes: 3 additions & 1 deletion frontend/packages/core/types/global.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ declare global {
}

namespace globalThis {
// eslint-disable-next-line no-var
/* eslint-disable no-var */
var __visualdl_instance_id__: string | string[] | undefined;
var webkitAudioContext: AudioContext | undefined;
/* eslint-enable no-var */
}
}

Expand Down
85 changes: 73 additions & 12 deletions frontend/packages/core/utils/audio.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
interface AudioPlayerOptions {
volumn: number;
context?: AudioContext;
volumn?: number;
onplay?: () => void;
onstop?: () => void;
}
Expand All @@ -10,6 +11,7 @@ export class AudioPlayer {
private source: AudioBufferSourceNode | null = null;
private buffer: AudioBuffer | null = null;
private decodedSampleRate: number = Number.NaN;
private contextFromOptions: boolean;

private startAt = 0;
private stopAt = 0;
Expand All @@ -19,7 +21,7 @@ export class AudioPlayer {

public playing = false;

public readonly options: AudioPlayerOptions;
public readonly options: Required<AudioPlayerOptions>;

get current() {
if (this.playing) {
Expand All @@ -39,7 +41,7 @@ export class AudioPlayer {
if (!this.buffer) {
return Number.NaN;
}
return Number.isNaN(this.decodedSampleRate) ? this.buffer.sampleRate : this.decodedSampleRate;
return this.decodedSampleRate;
}

get volumn() {
Expand All @@ -54,12 +56,16 @@ export class AudioPlayer {
this.gain.gain.value = value / 100;
}

constructor(options?: Partial<AudioPlayerOptions>) {
constructor(options?: AudioPlayerOptions) {
this.options = {
context: options?.context ?? new AudioContext(),
volumn: 100,
onplay: () => void 0,
onstop: () => void 0,
...options
};
this.context = new AudioContext();
this.contextFromOptions = !!options?.context;
this.context = this.options.context;
this.gain = this.context.createGain();
this.volumn = this.options.volumn;
}
Expand Down Expand Up @@ -87,16 +93,69 @@ export class AudioPlayer {
);
}

static getMp3SampleRate(buffer: ArrayBuffer) {
let arr = new Uint8Array(buffer);
if (String.fromCharCode.apply(null, Array.from(arr.slice(0, 3))) === 'ID3') {
arr = arr.slice(10);
let i = 0;
while (arr[i] !== 0x00) {
const size = arr[i + 4] * 0x100000000 + arr[i + 5] * 0x10000 + arr[i + 6] * 0x100 + arr[i + 7];
i += 10 + size;
}
}
let j = 0;
while (arr[j++] !== 0xff) {}
j--;
const header = arr.slice(j, j + 4);
const version = (header[1] & 0b00011000) >> 3;
const sampleRate = (header[2] & 0b00001100) >> 2;
if (version === 0b11) {
if (sampleRate === 0b00) {
return 44100;
} else if (sampleRate === 0b01) {
return 48000;
} else if (sampleRate === 0b10) {
return 32000;
}
} else if (version === 0b10) {
if (sampleRate === 0b00) {
return 22050;
} else if (sampleRate === 0b01) {
return 24000;
} else if (sampleRate === 0b10) {
return 16000;
}
} else if (version === 0b00) {
if (sampleRate === 0b00) {
return 11025;
} else if (sampleRate === 0b01) {
return 12000;
} else if (sampleRate === 0b10) {
return 8000;
}
}
return Number.NaN;
}

load(buffer: ArrayBuffer, type?: string) {
this.reset();
if (type === 'audio/wave') {
if (type === 'wav') {
this.decodedSampleRate = AudioPlayer.getWavSampleRate(buffer);
} else if (type === 'mpga' || type === 'mp3') {
this.decodedSampleRate = AudioPlayer.getMp3SampleRate(buffer);
} else {
this.decodedSampleRate = Number.NaN;
}

return this.context.decodeAudioData(buffer, audioBuffer => {
this.buffer = audioBuffer;
// safari doesn't return promise here
return new Promise<void>((resolve, reject) => {
this.context.decodeAudioData(
buffer,
audioBuffer => {
this.buffer = audioBuffer;
resolve();
},
reject
);
});
}

Expand All @@ -111,7 +170,7 @@ export class AudioPlayer {
this.stopAt = this.context.currentTime;
this.offset += this.stopAt - this.startAt;
this.playing = false;
this.options.onstop?.();
this.options.onstop();
this.source = null;
});
if (this.offset >= this.duration) {
Expand All @@ -120,7 +179,7 @@ export class AudioPlayer {
this.source.start(0, this.offset);
this.startAt = this.context.currentTime;
this.playing = true;
this.options.onplay?.();
this.options.onplay();
}

pause() {
Expand Down Expand Up @@ -159,7 +218,9 @@ export class AudioPlayer {

dispose() {
this.reset();
this.context.close();
if (!this.contextFromOptions) {
this.context.close();
}
this.source = null;
this.buffer = null;
}
Expand Down
11 changes: 11 additions & 0 deletions frontend/packages/core/utils/fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,17 @@ export const blobFetcher = async (url: string, options?: RequestInit): Promise<B
const res = await fetch(process.env.API_URL + url, addApiToken(options));
const data = await res.blob();
const disposition = res.headers.get('Content-Disposition');
// support safari
if (!data.arrayBuffer) {
data.arrayBuffer = async () =>
new Promise<ArrayBuffer>((resolve, reject) => {
const fileReader = new FileReader();
fileReader.addEventListener('load', e =>
e.target ? resolve(e.target.result as ArrayBuffer) : reject()
);
fileReader.readAsArrayBuffer(data);
});
}
let filename: string | null = null;
if (disposition && disposition.indexOf('attachment') !== -1) {
const matches = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/.exec(disposition);
Expand Down
2 changes: 2 additions & 0 deletions frontend/packages/core/utils/style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,8 @@ export const GlobalStyle = createGlobalStyle`

> .tippy-content {
padding: 0;
/* trigger bfc */
display: flow-root;
}

&[data-placement^='top'] > .tippy-arrow::before {
Expand Down
22 changes: 21 additions & 1 deletion frontend/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2676,6 +2676,13 @@
dependencies:
"@types/react" "*"

"@types/react-rangeslider@2.2.3":
version "2.2.3"
resolved "https://registry.yarnpkg.com/@types/react-rangeslider/-/react-rangeslider-2.2.3.tgz#b116483679b720f19fadf793067f3dd41b4f15e6"
integrity sha512-2LNR2FIKqSks7bSx4RWN3nCPR39ABG5cZUGRY5R0wLuEiMB6s6TWVxhfQa+5rm+mMhsdMGDB6Bm5pi6zq8kf8A==
dependencies:
"@types/react" "*"

"@types/react@*", "@types/react@16.9.43":
version "16.9.43"
resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.43.tgz#c287f23f6189666ee3bebc2eb8d0f84bcb6cdb6b"
Expand Down Expand Up @@ -4381,7 +4388,7 @@ class-utils@^0.3.5:
isobject "^3.0.0"
static-extend "^0.1.1"

classnames@2.2.6, classnames@^2.2.6:
classnames@2.2.6, classnames@^2.2.3, classnames@^2.2.6:
version "2.2.6"
resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce"
integrity sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==
Expand Down Expand Up @@ -11935,6 +11942,14 @@ react-is@16.13.1, react-is@^16.12.0, react-is@^16.13.1, react-is@^16.7.0, react-
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==

react-rangeslider@2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/react-rangeslider/-/react-rangeslider-2.2.0.tgz#4362b01f4f5a455f0815d371d496f69ca4c6b5aa"
integrity sha512-5K7Woa+cyqZ5wiW5+KhqGV+3+FiFxGKQ9rUxTMh52sObXVYEeBbfxFrp1eBvS8mRIxnUbHz9ppnFP0LhwOyNeg==
dependencies:
classnames "^2.2.3"
resize-observer-polyfill "^1.4.2"

react-refresh@0.8.3:
version "0.8.3"
resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.8.3.tgz#721d4657672d400c5e3c75d063c4a85fb2d5d68f"
Expand Down Expand Up @@ -12359,6 +12374,11 @@ requires-port@^1.0.0:
resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=

resize-observer-polyfill@^1.4.2:
version "1.5.1"
resolved "https://registry.yarnpkg.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464"
integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==

resolve-cwd@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a"
Expand Down
Loading