Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
c4542dc8eThis file is pinned to the selected release. Download the original to open it in your design tool.
import AudioIn from 'pins/audioin'
import Timer from 'timer'
export default class Microphone {
recording: boolean
constructor() {
this.recording = false
}
async record(durationMilliSec = 3000): Promise<ArrayBuffer> {
if (this.recording) {
throw new Error('already recording')
}
this.recording = true
const audio = new AudioIn()
const { sampleRate, numChannels, bitsPerSample } = audio
const byteRate = sampleRate * numChannels * (bitsPerSample >> 3)
const contentLength = (durationMilliSec / 1000) * byteRate
const buffer = new ArrayBuffer(44 + contentLength)
const view = new DataView(buffer)
try {
// set header
view.setUint8(0, 'R'.charCodeAt(0))
view.setUint8(1, 'I'.charCodeAt(0))
view.setUint8(2, 'F'.charCodeAt(0))
view.setUint8(3, 'F'.charCodeAt(0))
view.setUint32(4, 36 + contentLength, true)
view.setUint8(8, 'W'.charCodeAt(0))
view.setUint8(9, 'A'.charCodeAt(0))
view.setUint8(10, 'V'.charCodeAt(0))
view.setUint8(11, 'E'.charCodeAt(0))
view.setUint8(12, 'f'.charCodeAt(0))
view.setUint8(13, 'm'.charCodeAt(0))
view.setUint8(14, 't'.charCodeAt(0))
view.setUint8(15, ' '.charCodeAt(0))
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, (1 * bitsPerSample) >> 3, true)
view.setUint16(34, bitsPerSample, true)
view.setUint8(36, 'd'.charCodeAt(0))
view.setUint8(37, 'a'.charCodeAt(0))
view.setUint8(38, 't'.charCodeAt(0))
view.setUint8(39, 'a'.charCodeAt(0))
view.setUint32(40, contentLength, true)
const recordSamples = async (durationMilliSec): Promise<void> => {
const readingsPerSecond = 8
const sampleCount = Math.floor(audio.sampleRate / readingsPerSecond)
let samplesRemaining = (durationMilliSec / 1000) * audio.sampleRate
return new Promise((resolve) => {
let offset = 44
Timer.repeat((id) => {
//@ts-ignore
audio.read(sampleCount, buffer, offset)
offset += sampleCount * (bitsPerSample / 8)
samplesRemaining -= sampleCount
trace(`${samplesRemaining}\n`)
if (samplesRemaining <= 0) {
Timer.clear(id)
resolve()
}
}, 1000 / readingsPerSecond)
})
}
await recordSamples(durationMilliSec)
} finally {
this.recording = false
audio.close()
}
return view.buffer
}
}