129 lines
3.9 KiB
JavaScript
129 lines
3.9 KiB
JavaScript
let audioContext = new window.AudioContext()
|
|
let audioInput = null
|
|
let realAudioInput = null
|
|
let inputPoint = null
|
|
let audioRecorder = null
|
|
let socket = null
|
|
let analyserContext = null
|
|
let canvasWidth = null
|
|
let canvasHeight = null
|
|
let analyserNode = null
|
|
|
|
const drawBuffer = (width, height, context, data) => {
|
|
const step = Math.ceil(data.length / width)
|
|
const amp = height / 2
|
|
context.fillStyle = 'silver'
|
|
context.clearRect(0, 0, width, height)
|
|
for (let i = 0; i < width; i++) {
|
|
let min = 1.0
|
|
let max = -1.0
|
|
for (let j = 0; j < step; j++) {
|
|
let datum = data[(i * step) + j]
|
|
if (datum < min) min = datum
|
|
if (datum > max) max = datum
|
|
}
|
|
context.fillRect(i, (1 + min) * amp, 1, Math.max(1, (max - min) * amp))
|
|
}
|
|
}
|
|
|
|
const gotBuffers = buffers => {
|
|
let canvas = document.getElementById('wavedisplay')
|
|
drawBuffer(canvas.width, canvas.height, canvas.getContext('2d'), buffers[0])
|
|
audioRecorder.exportWAV(doneEncoding)
|
|
}
|
|
|
|
const doneEncoding = blob => {
|
|
const stream = window.ss.createStream()
|
|
document.getElementById('result').textContent = 'Analysing...'
|
|
window.ss(socket).emit('audio', stream)
|
|
window.ss.createBlobReadStream(blob).pipe(stream)
|
|
}
|
|
|
|
const toggleRecording = element => {
|
|
if (element.classList.contains('recording')) {
|
|
element.textContent = 'Listen'
|
|
audioRecorder.stop()
|
|
element.classList.remove('recording')
|
|
audioRecorder.getBuffers(gotBuffers)
|
|
return
|
|
}
|
|
element.textContent = 'Listening...'
|
|
if (!audioRecorder) return
|
|
element.classList.add('recording')
|
|
audioRecorder.clear()
|
|
audioRecorder.record()
|
|
}
|
|
|
|
const updateAnalysers = time => {
|
|
if (!analyserContext) {
|
|
const canvas = document.getElementById('analyser')
|
|
canvasWidth = canvas.width
|
|
canvasHeight = canvas.height
|
|
analyserContext = canvas.getContext('2d')
|
|
}
|
|
|
|
// analyzer draw code here
|
|
const SPACING = 3
|
|
const BAR_WIDTH = 1
|
|
const numBars = Math.round(canvasWidth / SPACING)
|
|
const freqByteData = new Uint8Array(analyserNode.frequencyBinCount)
|
|
analyserNode.getByteFrequencyData(freqByteData)
|
|
analyserContext.clearRect(0, 0, canvasWidth, canvasHeight)
|
|
analyserContext.fillStyle = '#F6D565'
|
|
analyserContext.lineCap = 'round'
|
|
const multiplier = analyserNode.frequencyBinCount / numBars
|
|
|
|
// Draw rectangle for each frequency bin.
|
|
for (let i = 0; i < numBars; ++i) {
|
|
let magnitude = 0
|
|
const offset = Math.floor(i * multiplier)
|
|
// gotta sum/average the block, or we miss narrow-bandwidth spikes
|
|
for (var j = 0; j < multiplier; j++) magnitude += freqByteData[offset + j]
|
|
magnitude = magnitude / multiplier
|
|
analyserContext.fillStyle = `hsl( ${Math.round((i * 360) / numBars)}, 100%, 50%)`
|
|
analyserContext.fillRect(i * SPACING, canvasHeight, BAR_WIDTH, -magnitude)
|
|
}
|
|
window.requestAnimationFrame(updateAnalysers)
|
|
}
|
|
|
|
const gotStream = stream => {
|
|
inputPoint = audioContext.createGain()
|
|
// Create an AudioNode from the stream.
|
|
realAudioInput = audioContext.createMediaStreamSource(stream)
|
|
audioInput = realAudioInput
|
|
audioInput.connect(inputPoint)
|
|
analyserNode = audioContext.createAnalyser()
|
|
analyserNode.fftSize = 2048
|
|
inputPoint.connect(analyserNode)
|
|
audioRecorder = new window.Recorder(inputPoint)
|
|
let zeroGain = audioContext.createGain()
|
|
zeroGain.gain.value = 0.0
|
|
inputPoint.connect(zeroGain)
|
|
zeroGain.connect(audioContext.destination)
|
|
updateAnalysers()
|
|
}
|
|
|
|
const initAudio = () => {
|
|
navigator.mediaDevices.getUserMedia({
|
|
audio: {
|
|
mandatory: {
|
|
googEchoCancellation: true,
|
|
googAutoGainControl: true,
|
|
googNoiseSuppression: true,
|
|
googHighpassFilter: true
|
|
},
|
|
optional: []
|
|
}
|
|
}).then(gotStream).catch(console.error)
|
|
}
|
|
|
|
const connect = () => {
|
|
socket = window.io.connect(window.location.origin)
|
|
window.ss(socket).on('news', (stream, data) => {
|
|
document.getElementById('result').textContent = data.text
|
|
})
|
|
}
|
|
|
|
connect()
|
|
initAudio()
|