Download frontend/src/utils/wavEncoder.ts from iahad/shaml: direct link, hf CLI and curl.
- Browser
- Download file 1.98 kB
-
https://huggingface.co/spaces/iahad/shaml/resolve/main/frontend/src/utils/wavEncoder.ts
- Command line
-
hf download hf://spaces/iahad/shaml/frontend/src/utils/wavEncoder.ts
-
curl -L -o wavEncoder.ts https://huggingface.co/spaces/iahad/shaml/resolve/main/frontend/src/utils/wavEncoder.ts
1.98 kB
| const TARGET_SAMPLE_RATE = 16000; | |
| function writeString(view: DataView, offset: number, text: string) { | |
| for (let i = 0; i < text.length; i++) { | |
| view.setUint8(offset + i, text.charCodeAt(i)); | |
| } | |
| } | |
| export function encodeWav(samples: Float32Array, sampleRate: number): Blob { | |
| const numChannels = 1; | |
| const bitsPerSample = 16; | |
| const blockAlign = (numChannels * bitsPerSample) / 8; | |
| const byteRate = sampleRate * blockAlign; | |
| const dataSize = samples.length * blockAlign; | |
| const buffer = new ArrayBuffer(44 + dataSize); | |
| const view = new DataView(buffer); | |
| writeString(view, 0, "RIFF"); | |
| view.setUint32(4, 36 + dataSize, true); | |
| writeString(view, 8, "WAVE"); | |
| writeString(view, 12, "fmt "); | |
| view.setUint32(16, 16, true); | |
| view.setUint16(20, 1, true); | |
| view.setUint16(22, numChannels, true); | |
| view.setUint32(24, sampleRate, true); | |
| view.setUint32(28, byteRate, true); | |
| view.setUint16(32, blockAlign, true); | |
| view.setUint16(34, bitsPerSample, true); | |
| writeString(view, 36, "data"); | |
| view.setUint32(40, dataSize, true); | |
| let offset = 44; | |
| for (let i = 0; i < samples.length; i++) { | |
| const s = Math.max(-1, Math.min(1, samples[i])); | |
| view.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7fff, true); | |
| offset += 2; | |
| } | |
| return new Blob([buffer], { type: "audio/wav" }); | |
| } | |
| export async function resampleTo16kMono(audioBuffer: AudioBuffer): Promise<Float32Array> { | |
| if (audioBuffer.sampleRate === TARGET_SAMPLE_RATE && audioBuffer.numberOfChannels === 1) { | |
| return audioBuffer.getChannelData(0).slice(); | |
| } | |
| const duration = audioBuffer.duration; | |
| const offline = new OfflineAudioContext( | |
| 1, | |
| Math.ceil(duration * TARGET_SAMPLE_RATE), | |
| TARGET_SAMPLE_RATE, | |
| ); | |
| const source = offline.createBufferSource(); | |
| source.buffer = audioBuffer; | |
| source.connect(offline.destination); | |
| source.start(0); | |
| const rendered = await offline.startRendering(); | |
| return rendered.getChannelData(0).slice(); | |
| } | |
| export { TARGET_SAMPLE_RATE }; | |