xxxxxxxxxx
94
// This is a test for audio quality of inverse DFT with non-linear frequency spacing
function map(x, min, max, targetMin, targetMax) {
return (x-min)/(max-min)*(targetMax-targetMin)+targetMin;
}
function generateFreqBands(N = 128, lowerHz = 20, higherHz = 20000) {
let freqArray = [];
for (let i = 0; i < N; i++) {
freqArray[i] = 2 ** map(i, 0, N-1, Math.log2(lowerHz), Math.log2(higherHz));
}
return freqArray;
}
function calcDFT(waveform, freqArray, sampleRate = 44100) {
let result = [];
freqArray.map((x, i) => {
let real = 0,
imag = 0;
waveform.map((amp, idx) => {
real += Math.cos(idx*2*Math.PI*x/sampleRate) * amp;
imag += Math.sin(idx*2*Math.PI*x/sampleRate) * amp;
});
result[i] = {
re: real/waveform.length,
im: imag/waveform.length,
freq: x
};
});
return result
}
function calcInverseDFT(spectrum, length = 2048, sampleRate = 44100) {
let result = [];
for (let i = 0; i < length; i++) {
let sum = 0;
spectrum.map(x => {
sum += x.re*Math.cos(i*2*Math.PI*x.freq/sampleRate)+
x.im*Math.sin(i*2*Math.PI*x.freq/sampleRate);
});
result[i] = sum;
}
return result;
}
// test
let data = [0.4, -0.2, 1, -0.1, 0.6, 0.2];
console.log(`DFT input: ${data}`);
let dftResult = calcDFT(data, data.map((_, i, arr) => i / arr.length), 1);
console.log(`DFT result:
real[${dftResult.map(x => x.re)}]
imag[${dftResult.map(x => x.im)}]`);
let idftResult = calcInverseDFT(dftResult, 6, 1);
console.log(`IDFT result: ${idftResult}`);
var audioCtx = new AudioContext();
// Create an empty buffer at the sample rate of the AudioContext
let myArrayBuffer = audioCtx.createBuffer(1, audioCtx.sampleRate, audioCtx.sampleRate);
// Fill the buffer with white noise;
// just random values between -1.0 and 1.0
for (let channel = 0; channel < myArrayBuffer.numberOfChannels; channel++) {
// This gives us the actual array that contains the data
let nowBuffering = myArrayBuffer.getChannelData(channel);
let data = new Array(myArrayBuffer.length);
for (let i = 0; i < data.length; i++) {
// Math.random() is in [0; 1.0]
// audio needs to be in [-1.0; 1.0]
data[i] = Math.random() * 2 - 1;
}
let dftResult = calcDFT(data, generateFreqBands(), audioCtx.sampleRate);
let idftResult = calcInverseDFT(dftResult, data.length, audioCtx.sampleRate);
/*data.map((x, i) => {
nowBuffering[i] = x/2;
});*/
idftResult.map((x, i) => {
nowBuffering[i] = x*2;
});
}
// Get an AudioBufferSourceNode.
// This is the AudioNode to use when we want to play an AudioBuffer
let source = audioCtx.createBufferSource();
// set the buffer in the AudioBufferSourceNode
source.buffer = myArrayBuffer;
// connect the AudioBufferSourceNode to the
// destination so we can hear the sound
source.connect(audioCtx.destination);
// start the source playing
source.loop = true;
source.start();