Skip to content

Instantly share code, notes, and snippets.

@huanggm
Created July 7, 2020 03:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save huanggm/bfc8d0c84afb5aaa3c28f5efcaeb4d62 to your computer and use it in GitHub Desktop.
Save huanggm/bfc8d0c84afb5aaa3c28f5efcaeb4d62 to your computer and use it in GitHub Desktop.
audio scripts
// 录音数据是共享内存的,所以在一个回调事件内是有效的
// 下一个回调事件内则会把上一份数据覆盖
const f32 = event.inputBuffer.getChannelData(0);
// 复制一份内存数据
const f32Ret = new Float32Array(f32);
// 把一个音频文件切片,分次上传
this.http.get('http://local.yuanfudao.ws:3000/assets/rec-001.wav', {
responseType: 'blob'
}).pipe(
switchMap(blob => {
const fileSize = blob.size;
console.log('fileSize: ', fileSize);
let start = 44;
const blobList = [];
while(start < fileSize) {
const end = start + 5000 > fileSize ? fileSize : start + 5000;
blobList.push(blob.slice(start, end));
start = end;
}
return zip(...blobList.map(item => new Observable(observer => {
const reader = new FileReader();
reader.onload = (e: any) => {
const base64=(/.+;\s*base64\s*,\s*(.+)$/i.exec(e.target.result)||[])[1];
observer.next(base64);
}
reader.readAsDataURL(item);
}) as Observable<string>
))
}),
tap((base64Arr: string[]) => {
console.log('tap tap', base64Arr);
this.wsSubject.next({type: 1, text: 'xxx', params: {audioType: 'pcm'}});
let index = 0;
const length = base64Arr.length;
const timer = setInterval(() => {
console.log('setInterval', index);
if (index < length) {
this.wsSubject.next({type: 2, packet: base64Arr[index], packetIndex: index});
index ++;
} else {
clearInterval(timer);
this.wsSubject.next({type: 3});
}
}, 500);
}),
catchError(e => {
console.log('eeee', e);
return of(null);
})
).subscribe();
// 合并多批次的数据为一个Float32Array
// 并把Float32Array转成Int16Array
private transArr32to16WithStep(bufferArr: Float32Array[][]) {
const f32ArrArr = bufferArr.map(b => b[0]); // 取单声道的数据
const totalLength = f32ArrArr.reduce((len, f32) => len + f32.length, 0);
const f32Arr = new Float32Array(totalLength);
let offset = 0;
for (let i = 0; i < f32ArrArr.length; i++) {
f32Arr.set(f32ArrArr[i], offset);
offset += f32ArrArr[i].length;
}
const int16Arr = new Int16Array(totalLength);
for (let i = 0; i < totalLength; i++) {
let s = Math.max(-1, Math.min(1, f32Arr[i]));
s = s < 0 ? s * 0x8000 : s * 0x7FFF;
int16Arr[i] = s;
}
return int16Arr;
}
// 把Int16Array转成wav文件
// 其实就是加上了wav文件头
private getWavFileFromBuffer(buffer16: Int16Array) {
console.log('buffer16 length', buffer16.length);
const size = buffer16.length;
const sampleRate = 16000;
const bitRate = 16;
// 编码数据 https://github.com/mattdiamond/Recorderjs https://www.cnblogs.com/blqw/p/3782420.html https://www.cnblogs.com/xiaoqi/p/6993912.html
const dataLength = size * ( bitRate / 8 );
const buffer = new ArrayBuffer(44 + dataLength);
const data = new DataView(buffer);
let offset = 0;
const writeString = function(str) {
for (let i = 0; i < str.length; i++, offset++) {
data.setUint8(offset, str.charCodeAt(i));
};
};
const write16 = function(v) {
data.setUint16(offset, v, true);
offset += 2;
};
const write32 = function(v) {
data.setUint32(offset, v, true);
offset += 4;
};
/* RIFF identifier */
writeString('RIFF');
/* RIFF chunk length */
write32(36 + dataLength);
/* RIFF type */
writeString('WAVE');
/* format chunk identifier */
writeString('fmt ');
/* format chunk length */
write32(16);
/* sample format (raw) */
write16(1);
/* channel count */
write16(1);
/* sample rate */
write32(sampleRate);
/* byte rate (sample rate * block align) */
write32(sampleRate * (bitRate / 8));
/* block align (channel count * bytes per sample) */
write16(bitRate / 8);
/* bits per sample */
write16(bitRate);
/* data chunk identifier */
writeString('data');
/* data chunk length */
write32(dataLength);
// 写入采样数据
for (let i = 0; i < size; i++, offset += 2) {
data.setInt16(offset, buffer16[i], true);
};
console.log(data.buffer);
const blob = new Blob([data.buffer], { type: 'audio/wav' })
const blobUrl = URL.createObjectURL(blob);
// @ts-ignore
document.querySelector('#audio-node-hgm').src = blobUrl;
const link = document.createElement('a');
link.href = blobUrl;
link.download = 'hello1.wav';
document.body.appendChild(link);
link.dispatchEvent(new MouseEvent('click', {
bubbles: true,
cancelable: true,
view: window
}))
}
// 使用btoa编码buffer到base64
const buffer16 = new ArrayBuffer(buffer32.length * 2);
const base64String = btoa(String.fromCharCode(...new Uint8Array(buffer16.buffer)));
// 使用第三方库编码
import {encode} from 'base64-arraybuffer'
const base64String = encode(buffer16);
// 使用FileReader Api读取buffer
const blob = new Blob([buffer]);
const reader = new FileReader();
reader.onloadend = (e: any) => {
// @ts-ignore
const base64 = (/.+;\s*base64\s*,\s*(.+)$/i.exec(reader.result) || [])[1];
}
reader.readAsDataURL(blob);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment