Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

语音可以可以下载到本地吗 #73

Open
QQ520 opened this issue Oct 31, 2023 · 5 comments
Open

语音可以可以下载到本地吗 #73

QQ520 opened this issue Oct 31, 2023 · 5 comments

Comments

@QQ520
Copy link

QQ520 commented Oct 31, 2023

No description provided.

@haoxiang1024
Copy link

在index.html中找到 function preview()的内容替换为以下内容
let headers = { 'Content-Type': 'text/plain' }; let voiceName = document.getElementsByName('voiceName')[0].value; let voiceFormat = document.getElementsByName('voiceFormat')[0].value; let token = document.getElementsByName('token')[0].value; let previewText = document.getElementsByName('previewText')[0].value; let ssml = createSSML(previewText, voiceName) if (token) { headers['Authorization'] = 'Bearer ' + token; } headers['Format'] = voiceFormat; let button = document.getElementById('previewButton'); button.disabled = true; let ctx = new AudioContext(); let audioBuffer; fetch('/api/ra', { method: 'post', headers: headers, body: ssml }).then(response => { if (response.status == 200) { return response.arrayBuffer() } else if (response.status == 401) { throw '无效的密钥'; } else { return response.text().then(text => Promise.reject(text)); } }).then(arrayBuffer => ctx.decodeAudioData(arrayBuffer)) .then(audio => { audioBuffer = audio; let player = ctx.createBufferSource(); player.buffer = audio; player.connect(ctx.destination); player.start(ctx.currentTime); }) .catch(reason => { alert(reason); }) .finally(() => { button.disabled = false; }); // 在最后添加以下代码 let downloadButton = document.getElementById('downloadButton'); downloadButton.addEventListener('click', () => { if (audioBuffer) { const audioData = exportWav(audioBuffer); const blob = new Blob([audioData], { type: 'audio/wav' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = 'audio.wav'; document.body.appendChild(a); a.click(); document.body.removeChild(a); } else { alert('请先预览音频'); } }); function exportWav(buffer) { const numberOfChannels = buffer.numberOfChannels; const sampleRate = buffer.sampleRate; const length = buffer.length; const duration = length / sampleRate; const bufferData = []; for (let channel = 0; channel < numberOfChannels; channel++) { bufferData.push(buffer.getChannelData(channel)); } const interleaved = interleave(bufferData, numberOfChannels); const dataview = encodeWAV(interleaved, numberOfChannels, sampleRate); return dataview.buffer; } function interleave(input, numberOfChannels) { const length = input[0].length * numberOfChannels; const output = new Float32Array(length); let offset = 0; for (let i = 0; i < input[0].length; i++) { for (let channel = 0; channel < numberOfChannels; channel++) { output[offset] = input[channel][i]; offset++; } } return output; } function encodeWAV(samples, numberOfChannels, sampleRate) { const buffer = new ArrayBuffer(44 + samples.length * 2); const view = new DataView(buffer); writeString(view, 0, 'RIFF'); view.setUint32(4, 36 + samples.length * 2, true); writeString(view, 8, 'WAVE'); writeString(view, 12, 'fmt '); view.setUint32(16, 16, true); // Sub-chunk 1 size view.setUint16(20, 1, true); // Audio format (1 for PCM) view.setUint16(22, numberOfChannels, true); // Number of channels view.setUint32(24, sampleRate, true); // Sample rate view.setUint32(28, sampleRate * numberOfChannels * 2, true); // Byte rate view.setUint16(32, numberOfChannels * 2, true); // Block align view.setUint16(34, 16, true); // Bits per sample writeString(view, 36, 'data'); view.setUint32(40, samples.length * 2, true); floatTo16BitPCM(view, 44, samples); return view; } function writeString(view, offset, string) { for (let i = 0; i < string.length; i++) { view.setUint8(offset + i, string.charCodeAt(i)); } } function floatTo16BitPCM(output, offset, input) { for (let i = 0; i < input.length; i++, offset += 2) { const s = Math.max(-1, Math.min(1, input[i])); output.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true); } }

@haoxiang1024
Copy link

经过测试可以使用

@shidahuilang
Copy link

image
可以下载音频

@edc-hui
Copy link

edc-hui commented Jun 29, 2024

@haoxiang1024 方便贴个完整的有格式的 preview()函数代码么?

萌新小白实在看不懂,按照你说的找到 function preview()的内容替换为以下内容, 替换之后一直在报语法错误,非常难定位 哪里有问题。

@haoxiang1024
Copy link

haoxiang1024 commented Jun 30, 2024 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants