{"ast":null,"code":"/*\r\n This file contains the code for LPC generation and its usage.\r\n The code used to generate the LPC was ported  from C++ code originally in the staRt iPad app.\r\n */\n\nimport { Complex } from '../Wave/lib/complex.jsx';\nconst _PI = 3.14159265;\n//var _LPC_ORDER = 80;\nconst _LPC_ORDER = 64;\nconst _MAX_LPC_ORDER = _LPC_ORDER + 1;\nconst SAMPLE_RATE = 44100;\nconst LPC_DISPLAY_RES = 64;\nlet delsmp = 0.0;\nconst computeLPC = audio_buffer => {\n  const lpc_coeffs = [];\n  for (let i = 0; i < _LPC_ORDER; i++) {\n    lpc_coeffs.push(0);\n  }\n  const buffer_size = audio_buffer.length;\n  const win = _hann_window(buffer_size);\n  const mean = _meanv(audio_buffer, buffer_size);\n  // remove the mean\n  audio_buffer = _vsadd(audio_buffer, -mean, buffer_size);\n\n  // I find the window to boost the overall signal level, instead of taper it\n  //audio_buffer = _vmul(audio_buffer, win, buffer_size);\n\n  //Original code uses temp buffer that we were able to remove in javascript version.\n  audio_buffer = _highPassFilter(audio_buffer, buffer_size);\n  const coeffs = _lpc_from_data(_LPC_ORDER, buffer_size, audio_buffer);\n  //lpc_coeffs[0] = 1;\n  for (let i = 0; i < _LPC_ORDER; i++) {\n    lpc_coeffs[i] = coeffs[i];\n  }\n  return lpc_coeffs;\n};\n\n// Originally this set the value of \"win\"\n// We should probably cache this result as it always generates the same value.\n// Dunno why this is ++i in the original code, out of bounds error? Fixed in mine.\n// CHECKED (Off by a bit for floating)\nconst _hann_window = buffer_size => {\n  const win = [];\n  //const W = 0.8165;\n  const W = 0.5; //<-- this is the value typically used in a hann window, not sure where .8165 comes from\n  for (let i = 0; i < buffer_size; ++i) {\n    win.push(W * (1 - Math.cos(2 * _PI * i / buffer_size)));\n  }\n  return win;\n};\nconst _f2_bandpass = buffer_size => {\n  const win = [];\n  const W = 0.5; // This value is not defined in the original code, use 0.5 for now, as hann_window\n  for (let i = 0; i < buffer_size; ++i) {\n    win.push(W * (1 - Math.cos(2 * _PI * i / buffer_size)));\n  }\n  return win;\n};\nconst _meanv = (buffer, buffer_size) => {\n  let sum = 0;\n  for (let i = 0; i < buffer_size; i++) {\n    sum += buffer[i];\n  }\n  return sum / (buffer_size * 1.0);\n};\nconst _vsadd = (audio_buffer, v, buffer_size) => {\n  const result = [];\n  for (let i = 0; i < buffer_size; i++) {\n    result.push(audio_buffer[i] + v);\n  }\n  return result;\n};\nconst _vmul = (buffer_a, buffer_b, buffer_size) => {\n  const result = [];\n  for (let i = 0; i < buffer_size; i++) {\n    result.push(buffer_a[i] * buffer_b[i]);\n  }\n  return result;\n};\n\n// Pre-emphasis filter with weight = .95 (.97 is typical)\nconst _highPassFilter = (inBuffer, winSize) => {\n  const result = [];\n  const MAGIC_FACTOR = .95; //.982;\n  for (let i = 0; i < winSize; i++) {\n    result.push(inBuffer[i] - MAGIC_FACTOR * delsmp);\n    delsmp = inBuffer[i];\n  }\n  return result;\n};\nconst initMatrix = (rows, cols) => {\n  const arr = [];\n  for (let x = 0; x < rows; x++) {\n    arr.push([]);\n    for (let y = 0; y < cols; y++) {\n      arr[x].push(0);\n    }\n  }\n  return arr;\n};\nconst _minvert = (size, mat) => {\n  let item,\n    row,\n    col = 0;\n  let temp = 0.0;\n  // Res appears to be result, but it is actually mat that is modified.\n  let res = initMatrix(_MAX_LPC_ORDER, _MAX_LPC_ORDER);\n  for (row = 1; row <= size; row++) {\n    for (col = 1; col <= size; col++) {\n      if (row == col) {\n        res[row][col] = 1.0;\n      } else {\n        res[row][col] = 0.0;\n      }\n    }\n  }\n  for (item = 1; item <= size; item++) {\n    // TODO Check if this == 0 is correctly handling floats.\n    if (mat[item][item] == 0) {\n      for (row = item; row <= size; row++) {\n        for (col = 1; col <= size; col++) {\n          mat[item][col] = mat[item][col] + mat[row][col];\n          res[item][col] = res[item][col] + res[col][row];\n        }\n      }\n    }\n    for (row = item; row <= size; row++) {\n      temp = mat[row][item];\n      if (temp != 0) {\n        for (col = 1; col <= size; col++) {\n          mat[row][col] = mat[row][col] / temp;\n          res[row][col] = res[row][col] / temp;\n        }\n      }\n    }\n    if (item != size) {\n      for (row = item + 1; row <= size; row++) {\n        temp = mat[row][item];\n        if (temp != 0) {\n          for (col = 1; col <= size; col++) {\n            mat[row][col] = mat[row][col] - mat[item][col];\n            res[row][col] = res[row][col] - res[item][col];\n          }\n        }\n      }\n    }\n  }\n  for (item = 2; item <= size; item++) {\n    for (row = 1; row < item; row++) {\n      temp = mat[row][item];\n      for (col = 1; col <= size; col++) {\n        mat[row][col] = mat[row][col] - temp * mat[item][col];\n        res[row][col] = res[row][col] - temp * res[item][col];\n      }\n    }\n  }\n  for (row = 1; row <= size; row++) {\n    for (col = 1; col <= size; col++) {\n      mat[row][col] = res[row][col];\n    }\n  }\n  return mat;\n};\n\n// result is an array size of _MAX_BLOCK_SIZE\nconst _autocorr = (size, data) => {\n  const result = []; // 1 D array of max size _MAX_BLOCK_SIZE\n\n  // assert(_MAX_BLOCK_SIZE* 2 >= size);\n  let i,\n    j,\n    k = 0; // long\n  let temp,\n    norm = 0.0; // double\n  for (i = 0; i < size / 2; i++) {\n    result.push(0);\n    for (j = 0; j < size - i - 1; j++) {\n      result[i] += data[i + j] * data[j];\n    }\n  }\n\n  // FOLLOWING CODE WAS COMMENTED OUT BECAUSE IT IS NOT USED\n  // find positive slope, store in j\n  // temp = result[0];\n  // j = Math.floor(size * 0.02); // Magic 0.02 number\n  // while (result[j] < temp && j < size / 2) {\n  //     temp = result[j];\n  //     j += 1;\n  // }\n\n  // temp = 0.0;\n  // for (i = j; i < size * 0.5; i++) {\n  //     if (result[i] > temp) {\n  //         j = i;\n  //         temp = result[i];\n  //     }\n  // }\n  norm = 1.0 / size / 2;\n  k = size / 2;\n  for (i = 0; i < size / 2; i++) {\n    result[i] *= (k - i) * norm;\n  }\n  // There is some weird code in the original source\n  // that sets the local value of j before returning. Dunno why.\n  // It is omited here.\n  return result;\n};\n\n// New autocorrelation that's much simpler -- not sure why the above has\n// the slope calculations and the size normalization\nconst _autocorr_simple = (order, data) => {\n  const result = [];\n  let max_value;\n  for (let i = 0; i <= order; i++) {\n    // Compute autocorrelation up to `order`\n    let sum = 0;\n    for (let j = 0; j < data.length - i; j++) {\n      sum += data[j] * data[j + i];\n    }\n    if (i == 0) {\n      // We normalize to RMS of the signal -- not sure if this is right\n      result.push(sum);\n      max_value = sum;\n    } else {\n      result.push(sum);\n    }\n  }\n  return result;\n};\nfunction addvector(a, b) {\n  return a.map((e, i) => e + b[i]);\n}\nconst levinsonDurbin = (autocorr, order) => {\n  // p = 1 -- base case\n  let alpha = [autocorr[1] / autocorr[0]];\n  let dot = (a, b) => a.map((x, i) => a[i] * b[i]).reduce((m, n) => m + n);\n  for (let i = 1; i < order; i++) {\n    // get arrays\n    let beta = [...alpha].reverse();\n    let r = autocorr.slice(1, i + 1);\n    let p = [...r].reverse();\n\n    // compute k, epsilon\n    let k = (autocorr[i + 1] - dot(p, alpha)) / (autocorr[0] - dot(r, alpha));\n    let epsilon = beta.map(x => -k * x);\n\n    // update alphas\n    alpha.push(0);\n    epsilon.push(k);\n    alpha = addvector(alpha, epsilon);\n\n    // iterate\n  }\n  return alpha;\n};\n\n// order is lpc order\n// size is audio_buffer size\n// data is audio_buffer\n// coeffs is the result, a double array the size of order.\nconst _lpc_from_data = (order, size, data) => {\n  const coeffs = [];\n  let r_mat = initMatrix(order, order); // Will be 2d array order x order size.\n  let i,\n    j = 0; // longs\n\n  const corr = _autocorr_simple(order, data);\n  const corr2 = _autocorr(size, data);\n  //console.log(corr)\n  //console.log(corr2)\n  //Toeplitz autocorrelation matrix (diaganol is rms)\n  for (i = 0; i < order; i++) {\n    for (j = 0; j < order; j++) {\n      r_mat[i][j] = corr[Math.abs(i - j)];\n    }\n  }\n  r_mat = _minvert(order - 1, r_mat);\n  for (i = 0; i < order - 1; i++) {\n    coeffs.push(0.0);\n    for (j = 0; j < order - 1; j++) {\n      coeffs[i] += r_mat[i + 1][j + 1] * corr[1 + j];\n    }\n  }\n  const coeffs2 = levinsonDurbin(corr, _LPC_ORDER);\n  // console.log(coeffs2);\n  // console.log(coeffs);\n  //coeffs2[0] = 1;\n  return coeffs2;\n};\n\n// theta is resused on every call to getFrequenciesFromLPC\n// so we declare it here as a global variable and initialize it only once in the function\n// getFrequenciesFromLPC.\nlet theta = null;\n\n// TODO Should pass an options dictionary instead of a long list of parameters.\n// Check this function\nconst getFrequenciesFromLPC = (lpcCoeffs, resolution, maxFrequency, sampleRate) => {\n  // H(z) = 1/[1-(a1*z^-1 + a2*z^-2 + ... + aN*z^-N)\n  if (theta === null) {\n    theta = new Array(resolution);\n    // Normalized frequency (in radians)\n    const inc = maxFrequency / resolution * 2 * Math.PI / sampleRate;\n    for (let i = 0; i < resolution; i++) {\n      theta[i] = inc * i;\n    }\n  }\n  const mags = new Array(resolution);\n  let maxMag = 0;\n  for (let i = 0; i < theta.length; i++) {\n    let temp = new Complex(0, 0);\n    for (let j = 0; j < lpcCoeffs.length; j++) {\n      // * (j+1) raises complex number to the power of (j+1)\n      let z = new Complex(Math.cos(theta[i] * (j + 1)), Math.sin(theta[i] * (j + 1)));\n      let az = new Complex(lpcCoeffs[j], 0).mul(z);\n      temp = temp.add(az);\n    }\n    let denom = new Complex(1, 0).sub(temp);\n    mags[i] = new Complex(1, 0).div(denom);\n  }\n  for (let i = 0; i < mags.length; i++) {\n    mags[i] = 1 * Math.log10(mags[i].abs());\n  }\n  return mags;\n};\nconst _biggerThanMyNeighbors = (mags, myLoc, numNeighbors) => {\n  let result = true;\n  // TODO Figure out this magic 5 number. How Local should be based on frequency resolution, atm 50hz.\n  // Lopsided to one side -- should make it even both sides &or take out completely if it's causing problems\n  for (let i = myLoc - 5; i < myLoc + numNeighbors; i++) {\n    result = result && mags[myLoc] > mags[i];\n  }\n  return result;\n};\nconst getPeaks = mags => {\n  const MIN_ENERGY = .1;\n  // To improve this we need to make sure we only take the peaks with the most energy for NUM_PEAKS.\n  // Peaks are when slope goes from positive to negative.\n  const HOW_LOCAL = Math.floor(mags.length / 25.0);\n  let slope = 0;\n  let i = 0;\n  const peaks = [];\n  while (slope == 0 && i < mags.length) {\n    if (mags[i] < mags[i + 1]) {\n      slope = 1;\n      break;\n    } else if (mags[i] > mags[i + 1]) {\n      slope = -1;\n    }\n    i++;\n  }\n  for (; i < mags.length; i++) {\n    if (slope == 1) {\n      if (mags[i] > mags[i + 1]) {\n        if (mags[i] > MIN_ENERGY) {\n          if (i > HOW_LOCAL && i < mags.length - HOW_LOCAL && _biggerThanMyNeighbors(mags, i, HOW_LOCAL)) ;\n          {\n            peaks.push(i);\n          }\n        }\n        slope = -1;\n      }\n    } else {\n      // slope == -1\n      if (mags[i] < mags[i + 1]) {\n        slope = 1;\n      }\n    }\n  }\n  return peaks;\n};\n\n// Initiate F2 array & boolean gate\nlet calculateFormants = false;\nlet runningF1 = [];\nlet runningF2 = [];\nlet runningF3 = [];\nlet averageF1;\nlet averageF2;\nlet averageF3;\nlet coefficients = [];\nlet counter = 0;\nlet counter2 = 0;\nlet runningLPC = new Float32Array(64);\nlet lpcCounter = 0;\n\n// helper function to add values to array\nconst addToRunningFormants = values => {\n  runningF1.push(values[0]);\n  runningF2.push(values[1]);\n  runningF3.push(values[2]);\n};\n\n// open the gate to capture running F2\nconst calculateRunningFormants = () => {\n  calculateFormants = true;\n  const formant1ValueElement = document.getElementById(\"formant1Value\");\n  formant1ValueElement.textContent = \"Tracking...\";\n  const formant2ValueElement = document.getElementById(\"formant2Value\");\n  formant2ValueElement.textContent = \"Tracking...\";\n  const formant3ValueElement = document.getElementById(\"formant3Value\");\n  formant3ValueElement.textContent = \"Tracking...\";\n};\n\n// close the gate & return value\nconst returnAndClearFormants = () => {\n  calculateFormants = false;\n  runningF1 = runningF1.filter(function (element) {\n    return element !== undefined;\n  });\n  runningF2 = runningF2.filter(function (element) {\n    return element !== undefined;\n  });\n  runningF3 = runningF3.filter(function (element) {\n    return element !== undefined;\n  });\n  if (runningF1 === undefined || runningF1.length == 0) {\n    averageF1 = \"Please try again, no formants were recorded.\";\n  } else {\n    averageF1 = (runningF1.reduce((accumulator, currentValue) => accumulator + currentValue, 0) / runningF1.length).toFixed(2);\n  }\n  if (runningF2 === undefined || runningF2.length == 0) {\n    averageF2 = \"Please try again, no formants were recorded.\";\n  } else {\n    averageF2 = (runningF2.reduce((accumulator, currentValue) => accumulator + currentValue, 0) / runningF2.length).toFixed(2);\n  }\n  if (runningF3 === undefined || runningF3.length == 0) {\n    averageF3 = \"Please try again, no formants were recorded.\";\n  } else {\n    averageF3 = (runningF3.reduce((accumulator, currentValue) => accumulator + currentValue, 0) / runningF3.length).toFixed(2);\n  }\n  const formant1ValueElement = document.getElementById(\"formant1Value\");\n  formant1ValueElement.textContent = averageF1;\n  const formant2ValueElement = document.getElementById(\"formant2Value\");\n  formant2ValueElement.textContent = averageF2;\n  const formant3ValueElement = document.getElementById(\"formant3Value\");\n  formant3ValueElement.textContent = averageF3;\n\n  //exportToCsv(coefficients);\n  // console.log(counter);\n  // console.log(counter2);\n\n  runningF1.length = 0;\n  runningF2.length = 0;\n  runningF3.length = 0;\n  coefficients.length = 0;\n  counter = 0;\n  counter2 = 0;\n  let overallLPC = calculateAverageLPC(runningLPC);\n  let roots = durandKerner(overallLPC);\n  let formants = extractFormants(roots, SAMPLE_RATE);\n  console.log(formants);\n};\nconst exportToCsv = (coefficients, filename = 'data.csv') => {\n  // Convert the array of arrays to a CSV string\n  const csvContent = coefficients.map(row => row.join(',')).join('\\n');\n\n  // Create a Blob with the CSV content\n  const blob = new Blob([csvContent], {\n    type: 'text/csv;charset=utf-8;'\n  });\n\n  // Create a link and trigger the download\n  const link = document.createElement('a');\n  let url = URL.createObjectURL(blob);\n  link.setAttribute('href', url);\n  link.setAttribute('download', filename);\n  link.style.visibility = 'hidden';\n  document.body.appendChild(link);\n  link.click();\n  document.body.removeChild(link);\n};\nconst isImpulse = array => {\n  let nonZeroCount = 0;\n  for (let i = 0; i < array.length; i++) {\n    if (array[i] !== 0) {\n      nonZeroCount++;\n      if (nonZeroCount > 1) {\n        return false; // More than one non-zero element\n      }\n    }\n  }\n  return nonZeroCount === 1; // True if exactly one non-zero element, false otherwise\n};\nconst isEmpty = myArray => {\n  let nanCounter = 0;\n  for (let i = 0; i < myArray.length; i++) {\n    if (isNaN(myArray[i])) {\n      nanCounter++;\n    }\n  }\n  let isEmpty = false;\n  if (nanCounter == myArray.length) {\n    isEmpty = true;\n  }\n  return isEmpty;\n};\nconst addToRunningLPC = coeffs => {\n  if (!isEmpty(coeffs)) {\n    if (!isImpulse(coeffs)) {\n      for (let i = 0; i <= coeffs.length; i++) {\n        runningLPC[i] += coeffs[i];\n      }\n      lpcCounter += 1;\n    }\n  }\n};\nconst calculateAverageLPC = () => {\n  let averageLPC = new Float32Array(LPC_DISPLAY_RES);\n  for (let i = 0; i < runningLPC.length; i++) {\n    averageLPC[i] = runningLPC[i] / lpcCounter;\n  }\n  runningLPC.fill(0);\n  lpcCounter = 0;\n  return averageLPC;\n};\n\n// UPDATED FORMANT ANALYSIS\n\n// // Function to calculate reflection coefficients from LPC coefficients\n// const calculateReflectionCoefficients = (inputLpcCoeffs) => {\n//     const lpcCoeffs = [...inputLpcCoeffs]; // Copy the input array\n//     const numCoeffs = lpcCoeffs.length - 1; // Exclude the first coefficient (assumed to be 1)\n//     const reflectionCoeffs = new Array(numCoeffs).fill(0);\n\n//     // Approximate total energy of the signal\n//     const E = new Array(numCoeffs + 1).fill(0);\n//     E[0] = lpcCoeffs.reduce((acc, coeff) => acc + coeff * coeff, 0);\n\n//     const K = new Array(numCoeffs).fill(0);\n\n//     for (let i = 1; i <= numCoeffs; i++) {\n//       let sum = 0;\n//       for (let j = 1; j <= i - 1; j++) {\n//         sum += lpcCoeffs[j] * lpcCoeffs[i - j] * K[j - 1];\n//       }\n//       // Apply regularization to improve stability\n//       const regularization = 1e-6; // Adjust as needed\n//       K[i - 1] = (lpcCoeffs[i] - sum) / (E[i - 1] + regularization);\n\n//       for (let j = 1; j <= i - 1; j++) {\n//         lpcCoeffs[j] -= K[i - 1] * lpcCoeffs[i - j];\n//       }\n\n//       E[i] = (1 - K[i - 1] * K[i - 1]) * E[i - 1];\n//       reflectionCoeffs[i - 1] = K[i - 1];\n//     }\n//     console.log(E)\n//     console.log(K)\n//     return reflectionCoeffs;\n// };\n\n//   // Function to calculate poles from reflection coefficients\n// const calculatePolesFromReflectionCoeffs = (reflectionCoeffs) => {\n//     let numPoles = reflectionCoeffs.length;\n//     let poles = [];\n\n//     for (let i = 0; i < numPoles; i++) {\n//       // Calculate the real and imaginary parts of the pole\n//       let realPart = reflectionCoeffs[i];\n//       let imaginaryPart = Math.sqrt(1 - realPart * realPart); // Assuming realPart is between -1 and 1\n\n//       // Create a complex number representing the pole\n//       poles.push({ realPart, imaginaryPart });\n//     }\n\n//     return poles;\n// }\n\n//   // Function to convert poles to formant frequencies in Hertz\n// const polesToFormantFrequencies = (poles, sampleRate) => {\n//     return poles.map(pole => {\n//       // Calculate the frequency in Hertz\n//       let frequency = (1 / (2 * Math.PI)) * Math.atan2(pole.imaginaryPart, pole.realPart) * sampleRate;\n//       return Math.abs(frequency); // Ensure positive frequencies\n//     });\n//   }\n\n//   // Function for post-processing formant frequencies (remove duplicates and sort)\n// const postProcessFormantFrequencies = (formantFrequencies) => {\n//     // Remove duplicate frequencies\n//     let uniqueFrequencies = Array.from(new Set(formantFrequencies));\n\n//     // Sort the frequencies in ascending order\n//     uniqueFrequencies.sort((a, b) => a - b);\n\n//     return uniqueFrequencies;\n// }\n\n// const approximateRoots = (coefficients) => {\n//     let n = coefficients.length - 1; // Degree of the polynomial\n//     let roots = new Array(n).fill(new Complex(0.4, 0.9)); // Initial guesses for roots\n\n//     for (let iter = 0; iter < maxIterations; iter++) {\n//         let converged = true;\n//         for (let i = 0; i < n; i++) {\n//             let newRoot = durandKerner(roots[i])\n\n//             if (Math.abs(newRoot.re - roots[i].re) > epsilon || Math.abs(newRoot.im - roots[i].im) > epsilon) {\n//                 converged = false;\n//             }\n//             roots[i] = newRoot;\n//         }\n//         if (converged) break;\n//     }\n//     return roots;\n// }\n\nconst durandKerner = coefficients => {\n  let coeffs = Array.from(coefficients.slice().reverse());\n  coeffs = coeffs.map(value => -value);\n  coeffs.push(1);\n  const tolerance = 1e-6;\n  const maxIterations = 100;\n  const n = coeffs.length - 1; // Degree of the polynomial\n\n  // Initial guesses for roots (using a small perturbation from 1)\n  let roots = Array.from({\n    length: n\n  }, (_, i) => new Complex(0.4, 0.8).pow(i));\n  for (let iter = 0; iter < maxIterations; iter++) {\n    let isConverged = true;\n    for (let i = 0; i < n; i++) {\n      let prod = new Complex(1, 0);\n      for (let j = 0; j < n; j++) {\n        if (i !== j) {\n          prod = prod.mul(roots[i].sub(roots[j]));\n        }\n      }\n      const numerator = evaluatePolynomial(coeffs, roots[i]);\n      const newRoot = roots[i].sub(numerator.div(prod));\n      if (newRoot.sub(roots[i]).abs() > tolerance) {\n        isConverged = false;\n      }\n      roots[i] = newRoot;\n    }\n    if (isConverged) {\n      break;\n    }\n  }\n  return roots.map(root => ({\n    real: root.re,\n    imag: root.im\n  }));\n};\nconst evaluatePolynomial = (coefficients, x) => {\n  let result = new Complex(0, 0);\n  for (let i = 0; i < coefficients.length; i++) {\n    result = result.add(new Complex(coefficients[i], 0).mul(x.pow(i)));\n  }\n  return result;\n};\nconst extractFormants = (roots, samplingRate) => {\n  let formants = roots.filter(root => root.imag !== 0) // Filter out non-complex roots\n  .map(root => {\n    const radius = Math.sqrt(root.real * root.real + root.imag * root.imag);\n    const angle = Math.atan2(root.imag, root.real);\n    return {\n      frequency: angle / (2 * Math.PI) * samplingRate,\n      bandwidth: -(1 / 2) * Math.log(radius) / Math.PI * samplingRate\n    };\n  }).filter(formant => formant.bandwidth > 0 && formant.bandwidth < 500) // Example bandwidth thresholds\n  .filter(formant => formant.frequency > 0 && formant.frequency < 4096).sort((a, b) => a.frequency - b.frequency);\n  return formants;\n};\nexport { computeLPC, extractFormants, durandKerner };","map":{"version":3,"names":["Complex","_PI","_LPC_ORDER","_MAX_LPC_ORDER","SAMPLE_RATE","LPC_DISPLAY_RES","delsmp","computeLPC","audio_buffer","lpc_coeffs","i","push","buffer_size","length","win","_hann_window","mean","_meanv","_vsadd","_highPassFilter","coeffs","_lpc_from_data","W","Math","cos","_f2_bandpass","buffer","sum","v","result","_vmul","buffer_a","buffer_b","inBuffer","winSize","MAGIC_FACTOR","initMatrix","rows","cols","arr","x","y","_minvert","size","mat","item","row","col","temp","res","_autocorr","data","j","k","norm","_autocorr_simple","order","max_value","addvector","a","b","map","e","levinsonDurbin","autocorr","alpha","dot","reduce","m","n","beta","reverse","r","slice","p","epsilon","r_mat","corr","corr2","abs","coeffs2","theta","getFrequenciesFromLPC","lpcCoeffs","resolution","maxFrequency","sampleRate","Array","inc","PI","mags","maxMag","z","sin","az","mul","add","denom","sub","div","log10","_biggerThanMyNeighbors","myLoc","numNeighbors","getPeaks","MIN_ENERGY","HOW_LOCAL","floor","slope","peaks","calculateFormants","runningF1","runningF2","runningF3","averageF1","averageF2","averageF3","coefficients","counter","counter2","runningLPC","Float32Array","lpcCounter","addToRunningFormants","values","calculateRunningFormants","formant1ValueElement","document","getElementById","textContent","formant2ValueElement","formant3ValueElement","returnAndClearFormants","filter","element","undefined","accumulator","currentValue","toFixed","overallLPC","calculateAverageLPC","roots","durandKerner","formants","extractFormants","console","log","exportToCsv","filename","csvContent","join","blob","Blob","type","link","createElement","url","URL","createObjectURL","setAttribute","style","visibility","body","appendChild","click","removeChild","isImpulse","array","nonZeroCount","isEmpty","myArray","nanCounter","isNaN","addToRunningLPC","averageLPC","fill","from","value","tolerance","maxIterations","_","pow","iter","isConverged","prod","numerator","evaluatePolynomial","newRoot","root","real","re","imag","im","samplingRate","radius","sqrt","angle","atan2","frequency","bandwidth","formant","sort"],"sources":["D:/Project/UC_Trains_Voice/react-demo/src/gavt/lib/lpc.js"],"sourcesContent":["/*\r\n This file contains the code for LPC generation and its usage.\r\n The code used to generate the LPC was ported  from C++ code originally in the staRt iPad app.\r\n */\r\n\r\n import {Complex} from '../Wave/lib/complex.jsx';\r\n\r\n const _PI = 3.14159265;\r\n //var _LPC_ORDER = 80;\r\n const _LPC_ORDER = 64;\r\n const _MAX_LPC_ORDER = _LPC_ORDER + 1;\r\n\r\n const SAMPLE_RATE = 44100;\r\n const LPC_DISPLAY_RES = 64;\r\n\r\n let delsmp = 0.0;\r\n \r\n const computeLPC = (audio_buffer) => {\r\n     const lpc_coeffs = [];\r\n     for (let i = 0; i < _LPC_ORDER; i++) {\r\n         lpc_coeffs.push(0);\r\n     }\r\n \r\n     const buffer_size = audio_buffer.length;\r\n     const win = _hann_window(buffer_size);\r\n \r\n     const mean = _meanv(audio_buffer, buffer_size);\r\n     // remove the mean\r\n     audio_buffer = _vsadd(audio_buffer, -mean, buffer_size);\r\n \r\n     // I find the window to boost the overall signal level, instead of taper it\r\n     //audio_buffer = _vmul(audio_buffer, win, buffer_size);\r\n \r\n     //Original code uses temp buffer that we were able to remove in javascript version.\r\n     audio_buffer = _highPassFilter(audio_buffer, buffer_size);\r\n \r\n     const coeffs = _lpc_from_data(_LPC_ORDER, buffer_size, audio_buffer);\r\n     //lpc_coeffs[0] = 1;\r\n     for (let i = 0; i < _LPC_ORDER; i++) {\r\n         lpc_coeffs[i] = coeffs[i];\r\n     }\r\n     return lpc_coeffs;\r\n };\r\n \r\n // Originally this set the value of \"win\"\r\n // We should probably cache this result as it always generates the same value.\r\n // Dunno why this is ++i in the original code, out of bounds error? Fixed in mine.\r\n // CHECKED (Off by a bit for floating)\r\n const _hann_window = (buffer_size) => {\r\n     const win = [];\r\n     //const W = 0.8165;\r\n     const W = 0.5; //<-- this is the value typically used in a hann window, not sure where .8165 comes from\r\n     for (let i = 0; i < buffer_size; ++i) {\r\n         win.push(W * (1 - Math.cos(2 * _PI * i / buffer_size)));\r\n     }\r\n     return win;\r\n };\r\n \r\n const _f2_bandpass = (buffer_size) => {\r\n     const win = [];\r\n     const W = 0.5; // This value is not defined in the original code, use 0.5 for now, as hann_window\r\n     for (let i = 0; i < buffer_size; ++i) {\r\n         win.push(W * (1 - Math.cos(2 * _PI * i / buffer_size)));\r\n     }\r\n     return win;\r\n };\r\n \r\n const _meanv = (buffer, buffer_size) => {\r\n     let sum = 0;\r\n     for (let i = 0; i < buffer_size; i++) {\r\n         sum += buffer[i];\r\n     }\r\n     return sum / (buffer_size * 1.0);\r\n };\r\n \r\n const _vsadd = (audio_buffer, v, buffer_size) => {\r\n     const result = [];\r\n     for (let i = 0; i < buffer_size; i++) {\r\n         result.push(audio_buffer[i] + v);\r\n     }\r\n     return result;\r\n };\r\n \r\n const _vmul = (buffer_a, buffer_b, buffer_size) => {\r\n     const result = [];\r\n     for (let i = 0; i < buffer_size; i++) {\r\n         result.push(buffer_a[i] * buffer_b[i]);\r\n     }\r\n     return result;\r\n };\r\n \r\n // Pre-emphasis filter with weight = .95 (.97 is typical)\r\n const _highPassFilter = (inBuffer, winSize) => {\r\n     const result = [];\r\n     const MAGIC_FACTOR = .95;//.982;\r\n     for (let i = 0; i < winSize; i++) {\r\n         result.push(inBuffer[i] - MAGIC_FACTOR * delsmp);\r\n         delsmp = inBuffer[i];\r\n     }\r\n     return result;\r\n };\r\n \r\n const initMatrix = (rows, cols) => {\r\n     const arr = [];\r\n     for (let x = 0; x < rows; x++) {\r\n         arr.push([]);\r\n         for (let y = 0; y < cols; y++) {\r\n             arr[x].push(0);\r\n         }\r\n     }\r\n     return arr;\r\n };\r\n \r\n const _minvert = (size, mat) => {\r\n     let item, row, col = 0;\r\n     let temp = 0.0;\r\n     // Res appears to be result, but it is actually mat that is modified.\r\n     let res = initMatrix(_MAX_LPC_ORDER, _MAX_LPC_ORDER);\r\n \r\n     for (row = 1; row <= size; row++) {\r\n         for (col = 1; col <= size; col++) {\r\n             if (row == col) {\r\n                 res[row][col] = 1.0;\r\n             }\r\n             else {\r\n                 res[row][col] = 0.0;\r\n             }\r\n         }\r\n     }\r\n \r\n     for (item = 1; item <= size; item++) {\r\n         // TODO Check if this == 0 is correctly handling floats.\r\n         if (mat[item][item] == 0) {\r\n             for (row = item; row <= size; row++) {\r\n                 for (col = 1; col <= size; col++) {\r\n                     mat[item][col] = mat[item][col] + mat[row][col];\r\n                     res[item][col] = res[item][col] + res[col][row];\r\n                 }\r\n             }\r\n         }\r\n \r\n         for (row = item; row <= size; row++) {\r\n             temp = mat[row][item];\r\n             if (temp != 0) {\r\n                 for (col = 1; col <= size; col++) {\r\n                     mat[row][col] = mat[row][col] / temp;\r\n                     res[row][col] = res[row][col] / temp;\r\n                 }\r\n             }\r\n         }\r\n \r\n         if (item != size) {\r\n             for (row = item + 1; row <= size; row++) {\r\n                 temp = mat[row][item];\r\n                 if (temp != 0) {\r\n                     for (col = 1; col <= size; col++) {\r\n                         mat[row][col] = mat[row][col] - mat[item][col];\r\n                         res[row][col] = res[row][col] - res[item][col];\r\n                     }\r\n                 }\r\n             }\r\n         }\r\n     }\r\n \r\n     for (item = 2; item <= size; item++) {\r\n         for (row = 1; row < item; row++) {\r\n             temp = mat[row][item];\r\n             for (col = 1; col <= size; col++) {\r\n                 mat[row][col] = mat[row][col] - temp * mat[item][col];\r\n                 res[row][col] = res[row][col] - temp * res[item][col];\r\n             }\r\n         }\r\n     }\r\n \r\n     for (row = 1; row <= size; row++) {\r\n         for (col = 1; col <= size; col++) {\r\n             mat[row][col] = res[row][col];\r\n         }\r\n     }\r\n \r\n     return mat;\r\n };\r\n \r\n // result is an array size of _MAX_BLOCK_SIZE\r\n const _autocorr = (size, data) => {\r\n     const result = []; // 1 D array of max size _MAX_BLOCK_SIZE\r\n \r\n     // assert(_MAX_BLOCK_SIZE* 2 >= size);\r\n     let i, j, k = 0; // long\r\n     let temp, norm = 0.0; // double\r\n     for (i = 0; i < size / 2; i++) {\r\n         result.push(0);\r\n         for (j = 0; j < size - i - 1; j++) {\r\n             result[i] += data[i + j] * data[j];\r\n         }\r\n     }\r\n     \r\n     // FOLLOWING CODE WAS COMMENTED OUT BECAUSE IT IS NOT USED\r\n     // find positive slope, store in j\r\n     // temp = result[0];\r\n     // j = Math.floor(size * 0.02); // Magic 0.02 number\r\n     // while (result[j] < temp && j < size / 2) {\r\n     //     temp = result[j];\r\n     //     j += 1;\r\n     // }\r\n \r\n     // temp = 0.0;\r\n     // for (i = j; i < size * 0.5; i++) {\r\n     //     if (result[i] > temp) {\r\n     //         j = i;\r\n     //         temp = result[i];\r\n     //     }\r\n     // }\r\n     norm = 1.0 / size / 2;\r\n     k = size / 2;\r\n     for (i = 0; i < size / 2; i++) {\r\n         result[i] *= (k - i) * norm;\r\n     }\r\n     // There is some weird code in the original source\r\n     // that sets the local value of j before returning. Dunno why.\r\n     // It is omited here.\r\n     return result;\r\n };\r\n \r\n // New autocorrelation that's much simpler -- not sure why the above has\r\n // the slope calculations and the size normalization\r\n const _autocorr_simple = (order, data) => {\r\n     const result = [];\r\n     let max_value;\r\n     for (let i = 0; i <= order; i++) { // Compute autocorrelation up to `order`\r\n         let sum = 0;\r\n         for (let j = 0; j < data.length - i; j++) {\r\n             sum += data[j] * data[j + i];\r\n         }\r\n         if (i == 0) {\r\n             // We normalize to RMS of the signal -- not sure if this is right\r\n             result.push(sum);\r\n             max_value = sum;\r\n         } else {\r\n             result.push(sum);\r\n         } \r\n     }\r\n     return result;\r\n };\r\n \r\n function addvector(a,b){\r\n     return a.map((e,i) => e + b[i]);\r\n }\r\n \r\n const levinsonDurbin = (autocorr, order) => {\r\n     // p = 1 -- base case\r\n     let alpha = [autocorr[1]/autocorr[0]];\r\n     let dot = (a, b) => a.map((x, i) => a[i] * b[i]).reduce((m, n) => m + n);\r\n \r\n     for (let i = 1; i < order; i++){\r\n         // get arrays\r\n         let beta = [...alpha].reverse()\r\n         let r = autocorr.slice(1, i+1)\r\n         let p = [...r].reverse()\r\n \r\n         // compute k, epsilon\r\n         let k = (autocorr[i+1] - dot(p, alpha))/(autocorr[0] - dot(r, alpha))\r\n         let epsilon = beta.map(x => -k * x)\r\n \r\n         // update alphas\r\n         alpha.push(0)\r\n         epsilon.push(k)\r\n \r\n         alpha = addvector(alpha, epsilon)\r\n \r\n         // iterate\r\n     }\r\n     \r\n     return alpha\r\n }\r\n \r\n // order is lpc order\r\n // size is audio_buffer size\r\n // data is audio_buffer\r\n // coeffs is the result, a double array the size of order.\r\n const _lpc_from_data = (order, size, data) => {\r\n     const coeffs = [];\r\n     let r_mat = initMatrix(order, order); // Will be 2d array order x order size.\r\n     let i, j = 0; // longs\r\n \r\n     const corr = _autocorr_simple(order, data);\r\n     const corr2 = _autocorr(size, data);\r\n     //console.log(corr)\r\n     //console.log(corr2)\r\n     //Toeplitz autocorrelation matrix (diaganol is rms)\r\n     for (i = 0; i < order; i++) {\r\n         for (j = 0; j < order; j++) {\r\n             r_mat[i][j] = corr[Math.abs(i - j)];\r\n         }\r\n     }\r\n     \r\n     r_mat = _minvert(order - 1, r_mat);\r\n \r\n     for (i = 0; i < order - 1; i++) {\r\n         coeffs.push(0.0);\r\n         for (j = 0; j < order - 1; j++) {\r\n             coeffs[i] += r_mat[i + 1][j + 1] * corr[1 + j];\r\n         }\r\n     }\r\n \r\n     const coeffs2 = levinsonDurbin(corr, _LPC_ORDER);\r\n     // console.log(coeffs2);\r\n     // console.log(coeffs);\r\n     //coeffs2[0] = 1;\r\n     return coeffs2;\r\n };\r\n \r\n // theta is resused on every call to getFrequenciesFromLPC\r\n // so we declare it here as a global variable and initialize it only once in the function\r\n // getFrequenciesFromLPC.\r\n let theta = null;\r\n \r\n // TODO Should pass an options dictionary instead of a long list of parameters.\r\n // Check this function\r\n const getFrequenciesFromLPC = (lpcCoeffs, resolution, maxFrequency, sampleRate) => {\r\n     // H(z) = 1/[1-(a1*z^-1 + a2*z^-2 + ... + aN*z^-N)\r\n     if (theta === null) {\r\n         theta = new Array(resolution);\r\n         // Normalized frequency (in radians)\r\n         const inc = (maxFrequency / resolution) * 2 * Math.PI / sampleRate;\r\n         for (let i = 0; i < resolution; i++) {\r\n             theta[i] = inc * i;\r\n         }\r\n     }\r\n     \r\n     const mags = new Array(resolution);\r\n     let maxMag = 0;\r\n     for (let i = 0; i < theta.length; i++) {\r\n         let temp = new Complex(0,0);\r\n         for (let j = 0; j < lpcCoeffs.length; j++) {\r\n             // * (j+1) raises complex number to the power of (j+1)\r\n             let z = new Complex(\r\n                 Math.cos(theta[i] * (j+1)),\r\n                 Math.sin(theta[i] * (j+1)));\r\n             let az = new Complex(lpcCoeffs[j],0).mul(z);\r\n             temp = temp.add(az);\r\n         }\r\n         let denom = new Complex(1,0).sub(temp);\r\n         mags[i] = new Complex(1,0).div(denom);\r\n         \r\n     }\r\n     \r\n     for (let i = 0; i < mags.length; i++) {\r\n         mags[i] = 1*Math.log10(mags[i].abs());\r\n     }\r\n     \r\n     return mags;\r\n };\r\n \r\n \r\n const _biggerThanMyNeighbors = (mags, myLoc, numNeighbors) => {\r\n     let result = true;\r\n     // TODO Figure out this magic 5 number. How Local should be based on frequency resolution, atm 50hz.\r\n     // Lopsided to one side -- should make it even both sides &or take out completely if it's causing problems\r\n     for (let i = myLoc - 5; i < myLoc + numNeighbors; i++) {\r\n         result = result && mags[myLoc] > mags[i];\r\n     }\r\n     return result;\r\n };\r\n \r\n const getPeaks = (mags) => {\r\n     const MIN_ENERGY = .1;\r\n     // To improve this we need to make sure we only take the peaks with the most energy for NUM_PEAKS.\r\n     // Peaks are when slope goes from positive to negative.\r\n     const HOW_LOCAL = Math.floor(mags.length / 25.0);\r\n     let slope = 0;\r\n     let i = 0;\r\n     const peaks = [];\r\n     while (slope == 0 && i < mags.length) {\r\n         if (mags[i] < mags[i + 1]) {\r\n             slope = 1;\r\n             break;\r\n         } else if (mags[i] > mags[i + 1]) {\r\n             slope = -1;\r\n         }\r\n         i++;\r\n     }\r\n     for (; i < mags.length; i++) {\r\n         if (slope == 1) {\r\n             if (mags[i] > mags[i + 1]) {\r\n                 if (mags[i] > MIN_ENERGY) {\r\n                     if (i > HOW_LOCAL && i < mags.length - HOW_LOCAL && _biggerThanMyNeighbors(mags, i, HOW_LOCAL));\r\n                     {\r\n                         peaks.push(i);\r\n                     }\r\n                 }\r\n                 slope = -1;\r\n             }\r\n         } else { // slope == -1\r\n             if (mags[i] < mags[i + 1]) {\r\n                 slope = 1;\r\n             }\r\n         }\r\n     }\r\n     return peaks;\r\n };\r\n \r\n // Initiate F2 array & boolean gate\r\n let calculateFormants = false;\r\n let runningF1 = [];\r\n let runningF2 = [];\r\n let runningF3 = [];\r\n let averageF1;\r\n let averageF2;\r\n let averageF3;\r\n let coefficients = [];\r\n let counter = 0;\r\n let counter2 = 0;\r\n let runningLPC = new Float32Array(64);\r\n let lpcCounter = 0;\r\n \r\n // helper function to add values to array\r\n const addToRunningFormants = (values) => {\r\n     runningF1.push(values[0]);\r\n     runningF2.push(values[1]);\r\n     runningF3.push(values[2]);\r\n }\r\n \r\n // open the gate to capture running F2\r\n const calculateRunningFormants = () => {\r\n     calculateFormants = true;\r\n     const formant1ValueElement = document.getElementById(\"formant1Value\");\r\n     formant1ValueElement.textContent = \"Tracking...\";\r\n     const formant2ValueElement = document.getElementById(\"formant2Value\");\r\n     formant2ValueElement.textContent = \"Tracking...\";\r\n     const formant3ValueElement = document.getElementById(\"formant3Value\");\r\n     formant3ValueElement.textContent = \"Tracking...\";\r\n }\r\n \r\n // close the gate & return value\r\n const returnAndClearFormants = () => {\r\n     calculateFormants = false;\r\n     \r\n     runningF1 = runningF1.filter(function( element ) {\r\n         return element !== undefined;\r\n     });\r\n     runningF2 = runningF2.filter(function( element ) {\r\n         return element !== undefined;\r\n     });\r\n     runningF3 = runningF3.filter(function( element ) {\r\n         return element !== undefined;\r\n     });\r\n     \r\n     if (runningF1 === undefined || runningF1.length == 0) {\r\n         averageF1 = \"Please try again, no formants were recorded.\";\r\n     } else {\r\n         averageF1 = (runningF1.reduce((accumulator, currentValue) => accumulator + currentValue, 0)/runningF1.length).toFixed(2);\r\n     }\r\n     if (runningF2 === undefined || runningF2.length == 0) {\r\n         averageF2 = \"Please try again, no formants were recorded.\";\r\n     } else {\r\n         averageF2 = (runningF2.reduce((accumulator, currentValue) => accumulator + currentValue, 0)/runningF2.length).toFixed(2);\r\n     }\r\n     if (runningF3 === undefined || runningF3.length == 0) {\r\n         averageF3 = \"Please try again, no formants were recorded.\";\r\n     } else {\r\n         averageF3 = (runningF3.reduce((accumulator, currentValue) => accumulator + currentValue, 0)/runningF3.length).toFixed(2);\r\n     }\r\n \r\n     const formant1ValueElement = document.getElementById(\"formant1Value\");\r\n     formant1ValueElement.textContent = averageF1;\r\n     const formant2ValueElement = document.getElementById(\"formant2Value\");\r\n     formant2ValueElement.textContent = averageF2;\r\n     const formant3ValueElement = document.getElementById(\"formant3Value\");\r\n     formant3ValueElement.textContent = averageF3;\r\n \r\n     //exportToCsv(coefficients);\r\n     // console.log(counter);\r\n     // console.log(counter2);\r\n \r\n     runningF1.length = 0;\r\n     runningF2.length = 0;\r\n     runningF3.length = 0;\r\n     coefficients.length = 0;\r\n     counter = 0;\r\n     counter2 = 0;\r\n \r\n     let overallLPC = calculateAverageLPC(runningLPC);\r\n     let roots = durandKerner(overallLPC);\r\n     let formants = extractFormants(roots, SAMPLE_RATE);\r\n     console.log(formants);\r\n }\r\n \r\n const exportToCsv = (coefficients, filename = 'data.csv') => {\r\n     // Convert the array of arrays to a CSV string\r\n     const csvContent = coefficients.map(row => row.join(',')).join('\\n');\r\n     \r\n     // Create a Blob with the CSV content\r\n     const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });\r\n     \r\n     // Create a link and trigger the download\r\n     const link = document.createElement('a');\r\n     let url = URL.createObjectURL(blob);\r\n     link.setAttribute('href', url);\r\n     link.setAttribute('download', filename);\r\n     link.style.visibility = 'hidden';\r\n     document.body.appendChild(link);\r\n     link.click();\r\n     document.body.removeChild(link);\r\n }\r\n \r\n const isImpulse = (array) => {\r\n     let nonZeroCount = 0;\r\n \r\n     for (let i = 0; i < array.length; i++) {\r\n         if (array[i] !== 0) {\r\n             nonZeroCount++;\r\n             if (nonZeroCount > 1) {\r\n                 return false; // More than one non-zero element\r\n             }\r\n         }\r\n     }\r\n \r\n     return nonZeroCount === 1; // True if exactly one non-zero element, false otherwise\r\n }\r\n \r\n const isEmpty = (myArray) => {\r\n     let nanCounter = 0;\r\n     for (let i = 0; i < myArray.length; i++){\r\n         if (isNaN(myArray[i])){\r\n             nanCounter++;\r\n         }\r\n     }\r\n     let isEmpty = false;\r\n     if (nanCounter == myArray.length) {\r\n         isEmpty = true;\r\n     }\r\n     return isEmpty\r\n }\r\n \r\n const addToRunningLPC = (coeffs) => {\r\n     if (!isEmpty(coeffs)){\r\n         if (!isImpulse(coeffs)) {\r\n             for (let i = 0; i <= coeffs.length; i++){\r\n                 runningLPC[i] += coeffs[i]\r\n             }\r\n             lpcCounter += 1;\r\n         }\r\n     }\r\n }\r\n \r\n const calculateAverageLPC = () => {\r\n     let averageLPC = new Float32Array(LPC_DISPLAY_RES);\r\n     for (let i = 0; i < runningLPC.length; i++){\r\n         averageLPC[i] = runningLPC[i]/lpcCounter;\r\n     }\r\n     runningLPC.fill(0);\r\n     lpcCounter = 0;\r\n     return averageLPC;\r\n }\r\n \r\n \r\n // UPDATED FORMANT ANALYSIS\r\n \r\n // // Function to calculate reflection coefficients from LPC coefficients\r\n // const calculateReflectionCoefficients = (inputLpcCoeffs) => {\r\n //     const lpcCoeffs = [...inputLpcCoeffs]; // Copy the input array\r\n //     const numCoeffs = lpcCoeffs.length - 1; // Exclude the first coefficient (assumed to be 1)\r\n //     const reflectionCoeffs = new Array(numCoeffs).fill(0);\r\n   \r\n //     // Approximate total energy of the signal\r\n //     const E = new Array(numCoeffs + 1).fill(0);\r\n //     E[0] = lpcCoeffs.reduce((acc, coeff) => acc + coeff * coeff, 0);\r\n   \r\n //     const K = new Array(numCoeffs).fill(0);\r\n   \r\n //     for (let i = 1; i <= numCoeffs; i++) {\r\n //       let sum = 0;\r\n //       for (let j = 1; j <= i - 1; j++) {\r\n //         sum += lpcCoeffs[j] * lpcCoeffs[i - j] * K[j - 1];\r\n //       }\r\n //       // Apply regularization to improve stability\r\n //       const regularization = 1e-6; // Adjust as needed\r\n //       K[i - 1] = (lpcCoeffs[i] - sum) / (E[i - 1] + regularization);\r\n   \r\n //       for (let j = 1; j <= i - 1; j++) {\r\n //         lpcCoeffs[j] -= K[i - 1] * lpcCoeffs[i - j];\r\n //       }\r\n   \r\n //       E[i] = (1 - K[i - 1] * K[i - 1]) * E[i - 1];\r\n //       reflectionCoeffs[i - 1] = K[i - 1];\r\n //     }\r\n //     console.log(E)\r\n //     console.log(K)\r\n //     return reflectionCoeffs;\r\n // };\r\n    \r\n   \r\n //   // Function to calculate poles from reflection coefficients\r\n // const calculatePolesFromReflectionCoeffs = (reflectionCoeffs) => {\r\n //     let numPoles = reflectionCoeffs.length;\r\n //     let poles = [];\r\n   \r\n //     for (let i = 0; i < numPoles; i++) {\r\n //       // Calculate the real and imaginary parts of the pole\r\n //       let realPart = reflectionCoeffs[i];\r\n //       let imaginaryPart = Math.sqrt(1 - realPart * realPart); // Assuming realPart is between -1 and 1\r\n   \r\n //       // Create a complex number representing the pole\r\n //       poles.push({ realPart, imaginaryPart });\r\n //     }\r\n   \r\n //     return poles;\r\n // }\r\n   \r\n //   // Function to convert poles to formant frequencies in Hertz\r\n // const polesToFormantFrequencies = (poles, sampleRate) => {\r\n //     return poles.map(pole => {\r\n //       // Calculate the frequency in Hertz\r\n //       let frequency = (1 / (2 * Math.PI)) * Math.atan2(pole.imaginaryPart, pole.realPart) * sampleRate;\r\n //       return Math.abs(frequency); // Ensure positive frequencies\r\n //     });\r\n //   }\r\n   \r\n //   // Function for post-processing formant frequencies (remove duplicates and sort)\r\n // const postProcessFormantFrequencies = (formantFrequencies) => {\r\n //     // Remove duplicate frequencies\r\n //     let uniqueFrequencies = Array.from(new Set(formantFrequencies));\r\n   \r\n //     // Sort the frequencies in ascending order\r\n //     uniqueFrequencies.sort((a, b) => a - b);\r\n   \r\n //     return uniqueFrequencies;\r\n // }\r\n \r\n // const approximateRoots = (coefficients) => {\r\n //     let n = coefficients.length - 1; // Degree of the polynomial\r\n //     let roots = new Array(n).fill(new Complex(0.4, 0.9)); // Initial guesses for roots\r\n \r\n //     for (let iter = 0; iter < maxIterations; iter++) {\r\n //         let converged = true;\r\n //         for (let i = 0; i < n; i++) {\r\n //             let newRoot = durandKerner(roots[i])\r\n \r\n //             if (Math.abs(newRoot.re - roots[i].re) > epsilon || Math.abs(newRoot.im - roots[i].im) > epsilon) {\r\n //                 converged = false;\r\n //             }\r\n //             roots[i] = newRoot;\r\n //         }\r\n //         if (converged) break;\r\n //     }\r\n //     return roots;\r\n // }\r\n \r\n const durandKerner = (coefficients) => {\r\n     let coeffs = Array.from(coefficients.slice().reverse());\r\n     coeffs = coeffs.map(value => -value);\r\n     coeffs.push(1);\r\n     const tolerance = 1e-6;\r\n     const maxIterations = 100;\r\n     const n = coeffs.length - 1; // Degree of the polynomial\r\n   \r\n     // Initial guesses for roots (using a small perturbation from 1)\r\n     let roots = Array.from({ length: n }, (_, i) => new Complex(0.4, 0.8).pow(i));\r\n   \r\n     for (let iter = 0; iter < maxIterations; iter++) {\r\n       let isConverged = true;\r\n   \r\n       for (let i = 0; i < n; i++) {\r\n         let prod = new Complex(1, 0);\r\n         for (let j = 0; j < n; j++) {\r\n           if (i !== j) {\r\n             prod = prod.mul(roots[i].sub(roots[j]));\r\n           }\r\n         }\r\n   \r\n         const numerator = evaluatePolynomial(coeffs, roots[i]);\r\n         const newRoot = roots[i].sub(numerator.div(prod));\r\n   \r\n         if (newRoot.sub(roots[i]).abs() > tolerance) {\r\n           isConverged = false;\r\n         }\r\n         roots[i] = newRoot;\r\n       }\r\n   \r\n       if (isConverged) {\r\n         break;\r\n       }\r\n     }\r\n   \r\n     return roots.map(root => ({ real: root.re, imag: root.im }));\r\n }\r\n   \r\n const evaluatePolynomial = (coefficients, x) => {\r\n     let result = new Complex(0, 0);\r\n     for (let i = 0; i < coefficients.length; i++) {\r\n         result = result.add(new Complex(coefficients[i], 0).mul(x.pow(i)));\r\n     }\r\n     return result;\r\n }\r\n \r\n const extractFormants = (roots, samplingRate) =>{\r\n     let formants = roots\r\n       .filter(root => root.imag !== 0) // Filter out non-complex roots\r\n       .map(root => {\r\n         const radius = Math.sqrt(root.real * root.real + root.imag * root.imag);\r\n         const angle = Math.atan2(root.imag, root.real);\r\n   \r\n         return {\r\n           frequency: (angle / (2 * Math.PI)) * samplingRate,\r\n           bandwidth: (-(1/2)*Math.log(radius) / Math.PI) * samplingRate\r\n         };\r\n       })\r\n       .filter(formant => formant.bandwidth > 0 && formant.bandwidth < 500) // Example bandwidth thresholds\r\n       .filter(formant => formant.frequency > 0 && formant.frequency < 4096)\r\n       .sort((a, b) => a.frequency - b.frequency);\r\n   \r\n     return formants;\r\n }\r\n\r\n export {computeLPC, extractFormants, durandKerner};"],"mappings":"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","ignoreList":[]},"metadata":{},"sourceType":"module","externalDependencies":[]}