({
frequency = 440,
durationSeconds = 0.8,
sampleRate = 8000,
} = {})
| 728 | } |
| 729 | |
| 730 | function createToneWavBase64({ |
| 731 | frequency = 440, |
| 732 | durationSeconds = 0.8, |
| 733 | sampleRate = 8000, |
| 734 | } = {}): string { |
| 735 | const sampleCount = Math.floor(sampleRate * durationSeconds) |
| 736 | const dataSize = sampleCount * 2 |
| 737 | const bytes = new Uint8Array(44 + dataSize) |
| 738 | const view = new DataView(bytes.buffer) |
| 739 | |
| 740 | writeAscii(bytes, 0, 'RIFF') |
| 741 | view.setUint32(4, 36 + dataSize, true) |
| 742 | writeAscii(bytes, 8, 'WAVE') |
| 743 | writeAscii(bytes, 12, 'fmt ') |
| 744 | view.setUint32(16, 16, true) |
| 745 | view.setUint16(20, 1, true) |
| 746 | view.setUint16(22, 1, true) |
| 747 | view.setUint32(24, sampleRate, true) |
| 748 | view.setUint32(28, sampleRate * 2, true) |
| 749 | view.setUint16(32, 2, true) |
| 750 | view.setUint16(34, 16, true) |
| 751 | writeAscii(bytes, 36, 'data') |
| 752 | view.setUint32(40, dataSize, true) |
| 753 | |
| 754 | for (let index = 0; index < sampleCount; index++) { |
| 755 | const envelope = Math.sin((Math.PI * index) / sampleCount) |
| 756 | const wave = Math.sin((2 * Math.PI * frequency * index) / sampleRate) |
| 757 | const sample = Math.round(wave * envelope * 0.25 * 32767) |
| 758 | view.setInt16(44 + index * 2, sample, true) |
| 759 | } |
| 760 | |
| 761 | return bytesToBase64(bytes) |
| 762 | } |
| 763 | |
| 764 | function writeAscii(bytes: Uint8Array, offset: number, value: string): void { |
| 765 | for (let index = 0; index < value.length; index++) { |
no test coverage detected