-
Notifications
You must be signed in to change notification settings - Fork 166
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #390 from F4310/play_sound
Playing Audio (WAV) through Vector
- Loading branch information
Showing
3 changed files
with
246 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
|
||
//Convert the WAV frame rate on the client machine and send the WAV file to be processed at /api-sdk/play_sound | ||
|
||
let processedAudioBlob = null; | ||
|
||
document.getElementById('fileInput').addEventListener('change', async () => { | ||
const fileInput = document.getElementById('fileInput'); | ||
if (!fileInput.files.length) { | ||
alert('Please, select a WAV file'); | ||
return; | ||
} | ||
|
||
const file = fileInput.files[0]; | ||
const arrayBuffer = await file.arrayBuffer(); | ||
const audioContext = new (window.AudioContext || window.webkitAudioContext)(); | ||
|
||
try { | ||
const audioBuffer = await audioContext.decodeAudioData(arrayBuffer); | ||
|
||
// adjust frame rate to 8000 Hz | ||
const newSampleRate = 8000; | ||
const newLength = Math.round(audioBuffer.length * newSampleRate / audioBuffer.sampleRate); | ||
const newBuffer = audioContext.createBuffer(audioBuffer.numberOfChannels, newLength, newSampleRate); | ||
|
||
for (let channel = 0; channel < audioBuffer.numberOfChannels; channel++) { | ||
const oldData = audioBuffer.getChannelData(channel); | ||
const newData = newBuffer.getChannelData(channel); | ||
|
||
for (let i = 0; i < newLength; i++) { | ||
const oldIndex = i * audioBuffer.sampleRate / newSampleRate; | ||
const index0 = Math.floor(oldIndex); | ||
const index1 = Math.min(index0 + 1, oldData.length - 1); | ||
const fraction = oldIndex - index0; | ||
|
||
newData[i] = oldData[index0] * (1 - fraction) + oldData[index1] * fraction; | ||
} | ||
} | ||
|
||
// Create a new WAV file | ||
processedAudioBlob = await bufferToWave(newBuffer); | ||
const url = URL.createObjectURL(processedAudioBlob); | ||
|
||
// play processed audio | ||
const audioOutput = document.getElementById('audioOutput'); | ||
audioOutput.src = url; | ||
audioOutput.play(); | ||
|
||
// show send button | ||
document.getElementById('uploadButton').style.display = 'inline-block'; | ||
} catch (error) { | ||
console.error('Error processing the file:', error); | ||
} | ||
}); | ||
|
||
function bufferToWave(abuffer) { | ||
const numOfChannels = abuffer.numberOfChannels; | ||
const length = abuffer.length * numOfChannels * 2 + 44; | ||
const buffer = new ArrayBuffer(length); | ||
const view = new DataView(buffer); | ||
let offset = 0; | ||
|
||
// Escrever cabeçalho WAV | ||
setString(view, offset, 'RIFF'); offset += 4; | ||
view.setUint32(offset, length - 8, true); offset += 4; | ||
setString(view, offset, 'WAVE'); offset += 4; | ||
setString(view, offset, 'fmt '); offset += 4; | ||
view.setUint32(offset, 16, true); offset += 4; // format size | ||
view.setUint16(offset, 1, true); offset += 2; // PCM format | ||
view.setUint16(offset, numOfChannels, true); offset += 2; // number of channels | ||
view.setUint32(offset, 8000, true); offset += 4; // sample rate | ||
view.setUint32(offset, 8000 * numOfChannels * 2, true); offset += 4; // byte rate | ||
view.setUint16(offset, numOfChannels * 2, true); offset += 2; // block align | ||
view.setUint16(offset, 16, true); offset += 2; // bits per sample | ||
|
||
setString(view, offset, 'data'); offset += 4; | ||
view.setUint32(offset, length - offset - 4, true); offset += 4; | ||
|
||
// Copiar os dados de áudio | ||
for (let channel = 0; channel < numOfChannels; channel++) { | ||
const channelData = abuffer.getChannelData(channel); | ||
for (let i = 0; i < channelData.length; i++) { | ||
view.setInt16(offset, channelData[i] * 0x7FFF, true); | ||
offset += 2; | ||
} | ||
} | ||
|
||
return new Blob([buffer], { type: 'audio/wav' }); | ||
} | ||
|
||
function setString(view, offset, string) { | ||
for (let i = 0; i < string.length; i++) { | ||
view.setUint8(offset + i, string.charCodeAt(i)); | ||
} | ||
} | ||
|
||
document.getElementById('uploadButton').addEventListener('click', async () => { | ||
if (!processedAudioBlob) { | ||
alert('No processed audio to send.'); | ||
return; | ||
} | ||
|
||
await uploadAudio(processedAudioBlob); | ||
}); | ||
|
||
async function uploadAudio(blob) { | ||
const formData = new FormData(); | ||
formData.append('sound', blob, 'processed.wav'); | ||
|
||
try { | ||
const dominio = window.location.hostname; | ||
esn = urlParams.get("serial"); | ||
const response = await fetch('/api-sdk/play_sound?serial='+esn, { | ||
method: 'POST', | ||
body: formData, | ||
}); | ||
|
||
if (!response.ok) { | ||
throw new Error('Erro to send audio: ' + response.statusText); | ||
} | ||
|
||
const result = await response.json(); | ||
console.log('Audio sent successfully:', result); | ||
} catch (error) { | ||
console.error('Error sending audio:', error); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters