{"ast":null,"code":"// Manually created for GAVT project on 2024-06-03, based on commit 10df1d9 of the original project\n\n/*\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;\nconst _LPC_ORDER = 64;\nconst _MAX_LPC_ORDER = _LPC_ORDER + 1;\n\n// Mannualy fixed for GAVT project on 2024-06-03\nconst SAMPLE_RATE = 44100;\nlet delsmp = 0.0;\nlet last = false;\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  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.0;\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.5;\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};\nconst _highPassFilter = (inBuffer, winSize) => {\n  const result = [];\n  const MAGIC_FACTOR = .95;\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};\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};\nconst levinsonDurbin = (autocorr, order) => {\n  // p = 1 -- base case\n  let alpha = [autocorr[1] / autocorr[0]];\n  const 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 = alpha.map((e, i) => e + epsilon[i]);\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 corr = _autocorr_simple(order, data);\n  let coeffs2 = levinsonDurbin(corr, _LPC_ORDER);\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.\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    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  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  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 = .315;\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  // Allowed more local peaks (halved value) to help with F2/F3 discrepancy in 'r' sound\n  const HOW_LOCAL = Math.floor(mags.length / 10.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};\nexport { computeLPC, getPeaks, getFrequenciesFromLPC };\n\n// FORMANT EXTRACTION CODE\n\n// Initiate F2 array & boolean gate\nlet runningF1 = [];\nlet runningF2 = [];\nlet runningF3 = [];\nlet averageF1;\nlet averageF2;\nlet averageF3;\nlet coefficients = [];\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// close the gate & return value\nconst returnAndClearFormants = calculateFormants => {\n  console.log(`calculateFormants: ${calculateFormants}`);\n  if (calculateFormants) {\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  } else if (!calculateFormants && last) {\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\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    console.log('Peak Picking Formants: ', averageF1, averageF2, averageF3);\n    console.log('');\n    runningF1.length = 0;\n    runningF2.length = 0;\n    runningF3.length = 0;\n    coefficients.length = 0;\n    let overallLPC = calculateAverageLPC(runningLPC);\n    let roots = durandKerner(overallLPC);\n    let formants = extractFormants(roots, SAMPLE_RATE);\n    console.log('Durand Kerner Formants (lower bandwidth is better): ', formants);\n    return formants;\n  }\n  last = calculateFormants;\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_ORDER);\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\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 < 400) // Example bandwidth thresholds\n  .filter(formant => formant.frequency > 20 && formant.frequency < 4096).sort((a, b) => a.frequency - b.frequency);\n  return formants;\n};\nexport { addToRunningFormants, addToRunningLPC, isImpulse, returnAndClearFormants, coefficients, extractFormants, durandKerner, runningLPC };","map":{"version":3,"names":["Complex","_PI","_LPC_ORDER","_MAX_LPC_ORDER","SAMPLE_RATE","delsmp","last","computeLPC","audio_buffer","lpc_coeffs","i","push","buffer_size","length","win","_hann_window","mean","_meanv","_vsadd","_vmul","_highPassFilter","coeffs","_lpc_from_data","W","Math","cos","buffer","sum","v","result","buffer_a","buffer_b","inBuffer","winSize","MAGIC_FACTOR","_autocorr_simple","order","data","max_value","j","levinsonDurbin","autocorr","alpha","dot","a","b","map","x","reduce","m","n","beta","reverse","r","slice","p","k","epsilon","e","size","corr","coeffs2","theta","getFrequenciesFromLPC","lpcCoeffs","resolution","maxFrequency","sampleRate","Array","inc","PI","mags","temp","z","sin","az","mul","add","denom","sub","div","log10","abs","_biggerThanMyNeighbors","myLoc","numNeighbors","getPeaks","MIN_ENERGY","HOW_LOCAL","floor","slope","peaks","runningF1","runningF2","runningF3","averageF1","averageF2","averageF3","coefficients","runningLPC","Float32Array","lpcCounter","addToRunningFormants","values","returnAndClearFormants","calculateFormants","console","log","filter","element","undefined","accumulator","currentValue","toFixed","overallLPC","calculateAverageLPC","roots","durandKerner","formants","extractFormants","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":["// Manually created for GAVT project on 2024-06-03, based on commit 10df1d9 of the original project\r\n\r\n/*\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 const _LPC_ORDER = 64;\r\n const _MAX_LPC_ORDER = _LPC_ORDER + 1;\r\n\r\n // Mannualy fixed for GAVT project on 2024-06-03\r\n const SAMPLE_RATE = 44100;\r\n \r\n let delsmp = 0.0;\r\n let last = false;\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 \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 \r\n     const coeffs = _lpc_from_data(_LPC_ORDER, buffer_size, audio_buffer);\r\n     //lpc_coeffs[0] = 1.0;\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.5;\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 const _highPassFilter = (inBuffer, winSize) => {\r\n     const result = [];\r\n     const MAGIC_FACTOR = .95;\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 // 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 const levinsonDurbin = (autocorr, order) => {\r\n     // p = 1 -- base case\r\n     let alpha = [autocorr[1]/autocorr[0]];\r\n     const 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 = alpha.map((e,i) => e + epsilon[i]);\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 \r\n     const corr = _autocorr_simple(order, data);\r\n     let coeffs2 = levinsonDurbin(corr, _LPC_ORDER);\r\n \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 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         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     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     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 = .315;\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     // Allowed more local peaks (halved value) to help with F2/F3 discrepancy in 'r' sound\r\n     const HOW_LOCAL = Math.floor(mags.length / 10.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 export {computeLPC, getPeaks, getFrequenciesFromLPC};\r\n \r\n \r\n // FORMANT EXTRACTION CODE\r\n \r\n // Initiate F2 array & boolean gate\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 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 // close the gate & return value\r\n const returnAndClearFormants = (calculateFormants) => {\r\n    console.log(`calculateFormants: ${calculateFormants}`);\r\n     if (calculateFormants) {\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     } else if (!calculateFormants && last) {\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         console.log('Peak Picking Formants: ', averageF1, averageF2, averageF3);\r\n         console.log('');\r\n \r\n         runningF1.length = 0;\r\n         runningF2.length = 0;\r\n         runningF3.length = 0;\r\n         coefficients.length = 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('Durand Kerner Formants (lower bandwidth is better): ', formants);\r\n\r\n         return formants;\r\n     }\r\n     last = calculateFormants;\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_ORDER);\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 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 < 400) // Example bandwidth thresholds\r\n       .filter(formant => formant.frequency > 20 && 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 {addToRunningFormants, addToRunningLPC, isImpulse, returnAndClearFormants, coefficients, extractFormants, durandKerner, runningLPC};"],"mappings":"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","ignoreList":[]},"metadata":{},"sourceType":"module","externalDependencies":[]}