-
Notifications
You must be signed in to change notification settings - Fork 4.4k
/
Copy pathbrowser_fft_utils.ts
131 lines (121 loc) · 4.34 KB
/
browser_fft_utils.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/**
* @license
* Copyright 2019 Google LLC. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* =============================================================================
*/
import * as tf from '@tensorflow/tfjs-core';
import {promisify} from 'util';
import {RawAudioData} from './types';
export async function loadMetadataJson(url: string):
Promise<{wordLabels: string[]}> {
const HTTP_SCHEME = 'http://';
const HTTPS_SCHEME = 'https://';
const FILE_SCHEME = 'file://';
if (url.indexOf(HTTP_SCHEME) === 0 || url.indexOf(HTTPS_SCHEME) === 0) {
const response = await fetch(url);
const parsed = await response.json();
return parsed;
} else if (url.indexOf(FILE_SCHEME) === 0) {
// tslint:disable-next-line:no-require-imports
const fs = require('fs');
const readFile = promisify(fs.readFile);
return JSON.parse(
await readFile(url.slice(FILE_SCHEME.length), {encoding: 'utf-8'}));
} else {
throw new Error(
`Unsupported URL scheme in metadata URL: ${url}. ` +
`Supported schemes are: http://, https://, and ` +
`(node.js-only) file://`);
}
}
let EPSILON: number = null;
/**
* Normalize the input into zero mean and unit standard deviation.
*
* This function is safe against divison-by-zero: In case the standard
* deviation is zero, the output will be all-zero.
*
* @param x Input tensor.
* @param y Output normalized tensor.
*/
export function normalize(x: tf.Tensor): tf.Tensor {
if (EPSILON == null) {
EPSILON = tf.backend().epsilon();
}
return tf.tidy(() => {
const {mean, variance} = tf.moments(x);
// Add an EPSILON to the denominator to prevent division-by-zero.
return tf.div(tf.sub(x, mean), tf.add(tf.sqrt(variance), EPSILON));
});
}
/**
* Z-Normalize the elements of a Float32Array.
*
* Subtract the mean and divide the result by the standard deviation.
*
* @param x The Float32Array to normalize.
* @return Noramlzied Float32Array.
*/
export function normalizeFloat32Array(x: Float32Array): Float32Array {
if (x.length < 2) {
throw new Error(
'Cannot normalize a Float32Array with fewer than 2 elements.');
}
if (EPSILON == null) {
EPSILON = tf.backend().epsilon();
}
return tf.tidy(() => {
const {mean, variance} = tf.moments(tf.tensor1d(x));
const meanVal = mean.arraySync() as number;
const stdVal = Math.sqrt(variance.arraySync() as number);
const yArray = Array.from(x).map(y => (y - meanVal) / (stdVal + EPSILON));
return new Float32Array(yArray);
});
}
export function getAudioContextConstructor(): AudioContext {
// tslint:disable-next-line:no-any
return (window as any).AudioContext || (window as any).webkitAudioContext;
}
export async function getAudioMediaStream(
audioTrackConstraints?: MediaTrackConstraints): Promise<MediaStream> {
return navigator.mediaDevices.getUserMedia({
audio: audioTrackConstraints == null ? true : audioTrackConstraints,
video: false
});
}
/**
* Play raw audio waveform
* @param rawAudio Raw audio data, including the waveform and the sampling rate.
* @param onEnded Callback function to execute when the playing ends.
*/
export function playRawAudio(
rawAudio: RawAudioData, onEnded: () => void|Promise<void>): void {
const audioContextConstructor =
// tslint:disable-next-line:no-any
(window as any).AudioContext || (window as any).webkitAudioContext;
const audioContext: AudioContext = new audioContextConstructor();
const arrayBuffer =
audioContext.createBuffer(1, rawAudio.data.length, rawAudio.sampleRateHz);
const nowBuffering = arrayBuffer.getChannelData(0);
nowBuffering.set(rawAudio.data);
const source = audioContext.createBufferSource();
source.buffer = arrayBuffer;
source.connect(audioContext.destination);
source.start();
source.onended = () => {
if (onEnded != null) {
onEnded();
}
};
}