index.ts
3.42 KB
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
import { compact } from 'lodash';
const opt = Object.prototype.toString;
export const bytesForHuman = (bytes: number, decimals = 2) => {
const units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];
let i = 0;
// eslint-disable-next-line no-plusplus
for (i; bytes > 1024; i++) {
bytes /= 1024;
}
return `${parseFloat(bytes.toFixed(decimals))} ${units[i]}`;
};
export const audioBufferToWav = (audioBuffer: AudioBuffer, len: number) => {
const numOfChan = audioBuffer.numberOfChannels;
const length = len * numOfChan * 2 + 44;
const buffer = new ArrayBuffer(length);
const view = new DataView(buffer);
const channels = [];
let i;
let sample;
let offset = 0;
let pos = 0;
// write WAVE header
// eslint-disable-next-line no-use-before-define
setUint32(0x46464952); // "RIFF"
// eslint-disable-next-line no-use-before-define
setUint32(length - 8); // file length - 8
// eslint-disable-next-line no-use-before-define
setUint32(0x45564157); // "WAVE"
// eslint-disable-next-line no-use-before-define
setUint32(0x20746d66); // "fmt " chunk
// eslint-disable-next-line no-use-before-define
setUint32(16); // length = 16
// eslint-disable-next-line no-use-before-define
setUint16(1); // PCM (uncompressed)
// eslint-disable-next-line no-use-before-define
setUint16(numOfChan);
// eslint-disable-next-line no-use-before-define
setUint32(audioBuffer.sampleRate);
// eslint-disable-next-line no-use-before-define
setUint32(audioBuffer.sampleRate * 2 * numOfChan); // avg. bytes/sec
// eslint-disable-next-line no-use-before-define
setUint16(numOfChan * 2); // block-align
// eslint-disable-next-line no-use-before-define
setUint16(16); // 16-bit (hardcoded in this demo)
// eslint-disable-next-line no-use-before-define
setUint32(0x61746164); // "data" - chunk
// eslint-disable-next-line no-use-before-define
setUint32(length - pos - 4); // chunk length
// write interleaved data
// eslint-disable-next-line no-plusplus
for (i = 0; i < audioBuffer.numberOfChannels; i++) {
// @ts-ignore
channels.push(audioBuffer.getChannelData(i));
}
while (pos < length) {
// eslint-disable-next-line no-plusplus
for (i = 0; i < numOfChan; i++) {
// interleave channels
sample = Math.max(-1, Math.min(1, channels[i][offset])); // clamp
// eslint-disable-next-line no-bitwise
sample = (0.5 + sample < 0 ? sample * 32768 : sample * 32767) | 0; // scale to 16-bit signed int
view.setInt16(pos, sample, true); // write 16-bit sample
pos += 2;
}
// eslint-disable-next-line no-plusplus
offset++; // next source sample
}
// create Blob
return new Blob([buffer], { type: 'audio/wav' });
function setUint16(data: number) {
view.setUint16(pos, data, true);
pos += 2;
}
function setUint32(data: number) {
view.setUint32(pos, data, true);
pos += 4;
}
};
export const getLyricTimeArr = (lyric: string): string[] => {
const times: string[] = [];
lyric.split('\n').forEach((item) => {
item = item.replace(/(^\s*)|(\s*$)/g, '');
times.push(item.substring(item.indexOf('[') + 1, item.indexOf(']')));
});
return compact(times);
};
export function isUndefined(obj: any): obj is undefined {
return obj === undefined;
}
export function isString(obj: any): obj is string {
return opt.call(obj) === '[object String]';
}
export const promiseToBoolean = (callback: Promise<any>) => callback.then(() => true).catch(() => false);