in 9-realtime/openai-realtime-console-example/src/lib/wavtools/lib/analysis/audio_analysis.js [94:157]
constructor(audioElement, audioBuffer = null) {
this.fftResults = [];
if (audioBuffer) {
/**
* Modified from
* https://stackoverflow.com/questions/75063715/using-the-web-audio-api-to-analyze-a-song-without-playing
*
* We do this to populate FFT values for the audio if provided an `audioBuffer`
* The reason to do this is that Safari fails when using `createMediaElementSource`
* This has a non-zero RAM cost so we only opt-in to run it on Safari, Chrome is better
*/
const { length, sampleRate } = audioBuffer;
const offlineAudioContext = new OfflineAudioContext({
length,
sampleRate,
});
const source = offlineAudioContext.createBufferSource();
source.buffer = audioBuffer;
const analyser = offlineAudioContext.createAnalyser();
analyser.fftSize = 8192;
analyser.smoothingTimeConstant = 0.1;
source.connect(analyser);
// limit is :: 128 / sampleRate;
// but we just want 60fps - cuts ~1s from 6MB to 1MB of RAM
const renderQuantumInSeconds = 1 / 60;
const durationInSeconds = length / sampleRate;
const analyze = (index) => {
const suspendTime = renderQuantumInSeconds * index;
if (suspendTime < durationInSeconds) {
offlineAudioContext.suspend(suspendTime).then(() => {
const fftResult = new Float32Array(analyser.frequencyBinCount);
analyser.getFloatFrequencyData(fftResult);
this.fftResults.push(fftResult);
analyze(index + 1);
});
}
if (index === 1) {
offlineAudioContext.startRendering();
} else {
offlineAudioContext.resume();
}
};
source.start(0);
analyze(1);
this.audio = audioElement;
this.context = offlineAudioContext;
this.analyser = analyser;
this.sampleRate = sampleRate;
this.audioBuffer = audioBuffer;
} else {
const audioContext = new AudioContext();
const track = audioContext.createMediaElementSource(audioElement);
const analyser = audioContext.createAnalyser();
analyser.fftSize = 8192;
analyser.smoothingTimeConstant = 0.1;
track.connect(analyser);
analyser.connect(audioContext.destination);
this.audio = audioElement;
this.context = audioContext;
this.analyser = analyser;
this.sampleRate = this.context.sampleRate;
this.audioBuffer = null;
}
}