speaker-calibration 2.1.11 → 2.1.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/main.js
CHANGED
|
@@ -763,7 +763,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var qrco
|
|
|
763
763
|
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
|
764
764
|
|
|
765
765
|
"use strict";
|
|
766
|
-
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var axios__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! axios */ \"./node_modules/axios/index.js\");\n/* harmony import */ var axios__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(axios__WEBPACK_IMPORTED_MODULE_0__);\n\r\n/**\r\n *\r\n */\r\nclass PythonServerAPI {\r\n static PYTHON_SERVER_URL = 'https://easyeyes-python-flask-server.herokuapp.com';\r\n\r\n static TEST_SERVER_URL = 'http://127.0.0.1:5000';\r\n /**\r\n * @param data- -\r\n * g = inverted impulse response, when convolved with the impulse\r\n * reponse, they cancel out.\r\n * @param data.payload\r\n * @param data.sampleRate\r\n * @param data.P\r\n * @param data-.payload\r\n * @param data-.sampleRate\r\n * @param data-.P\r\n * @returns\r\n * @example\r\n */\r\n getImpulseResponse = async ({mls, payload, sampleRate, P}) => {\r\n const task = 'impulse-response';\r\n let res = null;\r\n\r\n console.log({payload});\r\n\r\n const data = JSON.stringify({\r\n task,\r\n payload,\r\n 'sample-rate': sampleRate,\r\n mls,\r\n P,\r\n });\r\n\r\n await axios__WEBPACK_IMPORTED_MODULE_0___default()({\r\n method: 'post',\r\n baseURL: PythonServerAPI.PYTHON_SERVER_URL,\r\n url: `/task/${task}`,\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n },\r\n data,\r\n })\r\n .then(response => {\r\n res = response;\r\n })\r\n .catch(error => {\r\n throw error;\r\n });\r\n return res.data[task];\r\n };\r\n\r\n getInverseImpulseResponse = async ({payload,mls,lowHz,highHz}) => {\r\n const task = 'inverse-impulse-response';\r\n let res = null;\r\n\r\n console.log({payload});\r\n\r\n const data = JSON.stringify({\r\n task,\r\n payload,\r\n mls,\r\n lowHz,\r\n highHz\r\n });\r\n\r\n await axios__WEBPACK_IMPORTED_MODULE_0___default()({\r\n method: 'post',\r\n baseURL: PythonServerAPI.PYTHON_SERVER_URL,\r\n url: `/task/${task}`,\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n },\r\n data,\r\n })\r\n .then(response => {\r\n res = response;\r\n })\r\n .catch(error => {\r\n throw error;\r\n });\r\n\r\n return res.data[task];\r\n };\r\n\r\n getVolumeCalibration = async ({payload, sampleRate, lCalib}) => {\r\n const task = 'volume';\r\n let res = null;\r\n\r\n console.log({payload});\r\n\r\n const data = JSON.stringify({\r\n task,\r\n payload,\r\n 'sample-rate': sampleRate,\r\n lCalib,\r\n });\r\n\r\n await axios__WEBPACK_IMPORTED_MODULE_0___default()({\r\n method: 'post',\r\n baseURL: PythonServerAPI.PYTHON_SERVER_URL,\r\n url: `/task/${task}`,\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n },\r\n data,\r\n })\r\n .then(response => {\r\n res = response;\r\n })\r\n .catch(error => {\r\n throw error;\r\n });\r\n\r\n return res.data[task];\r\n };\r\n\r\n getVolumeCalibrationParameters = async ({inDBValues, outDBSPLValues, lCalib}) => {\r\n const task = 'volume-parameters';\r\n let res = null;\r\n\r\n const data = JSON.stringify({\r\n task,\r\n inDBValues,\r\n outDBSPLValues,\r\n lCalib,\r\n });\r\n\r\n await axios__WEBPACK_IMPORTED_MODULE_0___default()({\r\n method: 'post',\r\n baseURL: PythonServerAPI.PYTHON_SERVER_URL, //server\r\n url: `/task/${task}`,\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n },\r\n data,\r\n })\r\n .then(response => {\r\n res = response;\r\n })\r\n .catch(error => {\r\n throw error;\r\n });\r\n\r\n // console.log(res.data[task]);\r\n //below is an example of res.data[task]\r\n //{\r\n // R: 16.56981076554259,\r\n // RMSError: 1.9289162528535229\r\n // T: -47.79799120884434,\r\n // W: 61.0485247483732,\r\n // backgroundDBSPL: 43.88233142069752,\r\n // gainDBSPL: -128.24742161208985\r\n //}\r\n return res.data[task];\r\n };\r\n}\r\n\r\n/* harmony default export */ __webpack_exports__[\"default\"] = (PythonServerAPI);\r\n\n\n//# sourceURL=webpack://speakerCalibrator/./src/server/PythonServerAPI.js?");
|
|
766
|
+
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var axios__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! axios */ \"./node_modules/axios/index.js\");\n/* harmony import */ var axios__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(axios__WEBPACK_IMPORTED_MODULE_0__);\n\r\n/**\r\n *\r\n */\r\nclass PythonServerAPI {\r\n static PYTHON_SERVER_URL = 'https://easyeyes-python-flask-server.herokuapp.com';\r\n\r\n static TEST_SERVER_URL = 'http://127.0.0.1:5000';\r\n /**\r\n * @param data- -\r\n * g = inverted impulse response, when convolved with the impulse\r\n * reponse, they cancel out.\r\n * @param data.payload\r\n * @param data.sampleRate\r\n * @param data.P\r\n * @param data-.payload\r\n * @param data-.sampleRate\r\n * @param data-.P\r\n * @returns\r\n * @example\r\n */\r\n getImpulseResponse = async ({mls, payload, sampleRate, P}) => {\r\n const task = 'impulse-response';\r\n let res = null;\r\n\r\n console.log({payload});\r\n\r\n const data = JSON.stringify({\r\n task,\r\n payload,\r\n 'sample-rate': sampleRate,\r\n mls,\r\n P,\r\n });\r\n\r\n await axios__WEBPACK_IMPORTED_MODULE_0___default()({\r\n method: 'post',\r\n baseURL: PythonServerAPI.PYTHON_SERVER_URL,\r\n url: `/task/${task}`,\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n },\r\n data,\r\n })\r\n .then(response => {\r\n res = response;\r\n })\r\n .catch(error => {\r\n throw error;\r\n });\r\n return res.data[task];\r\n };\r\n\r\n getPSD = async ({unconv_rec, conv_rec}) => {\r\n const task = 'psd';\r\n let res = null;\r\n\r\n const data = JSON.stringify({\r\n task,\r\n unconv_rec,\r\n conv_rec,\r\n });\r\n\r\n await axios__WEBPACK_IMPORTED_MODULE_0___default()({\r\n method: 'post',\r\n baseURL: PythonServerAPI.PYTHON_SERVER_URL,\r\n url: `/task/${task}`,\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n },\r\n data,\r\n })\r\n .then(response => {\r\n res = response;\r\n })\r\n .catch(error => {\r\n throw error;\r\n });\r\n return res.data[task];\r\n };\r\n\r\n getInverseImpulseResponse = async ({payload,mls,lowHz,highHz}) => {\r\n const task = 'inverse-impulse-response';\r\n let res = null;\r\n\r\n console.log({payload});\r\n\r\n const data = JSON.stringify({\r\n task,\r\n payload,\r\n mls,\r\n lowHz,\r\n highHz\r\n });\r\n\r\n await axios__WEBPACK_IMPORTED_MODULE_0___default()({\r\n method: 'post',\r\n baseURL: PythonServerAPI.PYTHON_SERVER_URL,\r\n url: `/task/${task}`,\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n },\r\n data,\r\n })\r\n .then(response => {\r\n res = response;\r\n })\r\n .catch(error => {\r\n throw error;\r\n });\r\n\r\n return res.data[task];\r\n };\r\n\r\n getVolumeCalibration = async ({payload, sampleRate, lCalib}) => {\r\n const task = 'volume';\r\n let res = null;\r\n\r\n console.log({payload});\r\n\r\n const data = JSON.stringify({\r\n task,\r\n payload,\r\n 'sample-rate': sampleRate,\r\n lCalib,\r\n });\r\n\r\n await axios__WEBPACK_IMPORTED_MODULE_0___default()({\r\n method: 'post',\r\n baseURL: PythonServerAPI.PYTHON_SERVER_URL,\r\n url: `/task/${task}`,\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n },\r\n data,\r\n })\r\n .then(response => {\r\n res = response;\r\n })\r\n .catch(error => {\r\n throw error;\r\n });\r\n\r\n return res.data[task];\r\n };\r\n\r\n getVolumeCalibrationParameters = async ({inDBValues, outDBSPLValues, lCalib}) => {\r\n const task = 'volume-parameters';\r\n let res = null;\r\n\r\n const data = JSON.stringify({\r\n task,\r\n inDBValues,\r\n outDBSPLValues,\r\n lCalib,\r\n });\r\n\r\n await axios__WEBPACK_IMPORTED_MODULE_0___default()({\r\n method: 'post',\r\n baseURL: PythonServerAPI.PYTHON_SERVER_URL, //server\r\n url: `/task/${task}`,\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n },\r\n data,\r\n })\r\n .then(response => {\r\n res = response;\r\n })\r\n .catch(error => {\r\n throw error;\r\n });\r\n\r\n // console.log(res.data[task]);\r\n //below is an example of res.data[task]\r\n //{\r\n // R: 16.56981076554259,\r\n // RMSError: 1.9289162528535229\r\n // T: -47.79799120884434,\r\n // W: 61.0485247483732,\r\n // backgroundDBSPL: 43.88233142069752,\r\n // gainDBSPL: -128.24742161208985\r\n //}\r\n return res.data[task];\r\n };\r\n}\r\n\r\n/* harmony default export */ __webpack_exports__[\"default\"] = (PythonServerAPI);\r\n\n\n//# sourceURL=webpack://speakerCalibrator/./src/server/PythonServerAPI.js?");
|
|
767
767
|
|
|
768
768
|
/***/ }),
|
|
769
769
|
|
|
@@ -796,7 +796,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _myE
|
|
|
796
796
|
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
|
797
797
|
|
|
798
798
|
"use strict";
|
|
799
|
-
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _audioCalibrator__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../audioCalibrator */ \"./src/tasks/audioCalibrator.js\");\n/* harmony import */ var _mlsGen_mlsGenInterface__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./mlsGen/mlsGenInterface */ \"./src/tasks/impulse-response/mlsGen/mlsGenInterface.js\");\n/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../utils */ \"./src/utils.js\");\n\r\n\r\n\r\n\r\n\r\n/**\r\n *\r\n */\r\nclass ImpulseResponse extends _audioCalibrator__WEBPACK_IMPORTED_MODULE_0__[\"default\"] {\r\n /**\r\n * Default constructor. Creates an instance with any number of paramters passed or the default parameters defined here.\r\n *\r\n * @param {Object<boolean, number, number, number>} calibratorParams - paramter object\r\n * @param {boolean} [calibratorParams.download = false] - boolean flag to download captures\r\n * @param {number} [calibratorParams.mlsOrder = 18] - order of the MLS to be generated\r\n * @param {number} [calibratorParams.numCaptures = 5] - number of captures to perform\r\n * @param {number} [calibratorParams.numMLSPerCapture = 4] - number of bursts of MLS per capture\r\n */\r\n constructor({download = false, mlsOrder = 18, numCaptures = 3, numMLSPerCapture = 4, lowHz = 20, highHz = 10000}) {\r\n super(numCaptures, numMLSPerCapture);\r\n this.#mlsOrder = parseInt(mlsOrder, 10);\r\n this.#P = 2 ** mlsOrder - 1;\r\n this.#download = download;\r\n this.#mls = [];\r\n this.#lowHz = lowHz;\r\n this.#highHz = highHz;\r\n }\r\n\r\n /** @private */\r\n #download;\r\n\r\n /** @private */\r\n #mlsGenInterface;\r\n\r\n /** @private */\r\n #mlsBufferView;\r\n\r\n /** @private */\r\n invertedImpulseResponse = null;\r\n\r\n /** @private */\r\n impulseResponses = [];\r\n\r\n /** @private */\r\n #mlsOrder;\r\n\r\n /** @private */\r\n #lowHz;\r\n\r\n /** @private */\r\n #highHz;\r\n\r\n /** @private */\r\n #mls;\r\n\r\n /** @private */\r\n #P;\r\n\r\n /** @private */\r\n #audioContext;\r\n\r\n /** @private */\r\n TAPER_SECS = 5;\r\n\r\n /** @private */\r\n offsetGainNode;\r\n\r\n /** @private */\r\n convolution;\r\n\r\n /** .\r\n * .\r\n * .\r\n * Sends all the computed impulse responses to the backend server for processing\r\n *\r\n * @returns sets the resulting inverted impulse response to the class property\r\n * @example\r\n */\r\n sendImpulseResponsesToServerForProcessing = async () => {\r\n const computedIRs = await Promise.all(this.impulseResponses);\r\n const mls = this.#mls;\r\n const lowHz = this.#lowHz;\r\n const highHz = this.#highHz;\r\n this.emit('update', {message: `computing the IIR...`});\r\n return this.pyServerAPI\r\n .getInverseImpulseResponse({\r\n payload: computedIRs.slice(0, this.numCaptures),\r\n mls,\r\n lowHz,\r\n highHz\r\n })\r\n .then(res => {\r\n console.log(res);\r\n this.emit('update', {message: `done computing the IIR...`});\r\n this.invertedImpulseResponse = res[\"iir\"];\r\n this.convolution = res[\"convolution\"];\r\n })\r\n .catch(err => {\r\n // this.emit('InvertedImpulseResponse', {res: false});\r\n console.error(err);\r\n });\r\n };\r\n\r\n /** .\r\n * .\r\n * .\r\n * Sends the recorded signal, or a given csv string of a signal, to the back end server for processing\r\n *\r\n * @param {<array>String} signalCsv - Optional csv string of a previously recorded signal, if given, this signal will be processed\r\n * @example\r\n */\r\n sendRecordingToServerForProcessing = signalCsv => {\r\n const allSignals = this.getAllRecordedSignals();\r\n const numSignals = allSignals.length;\r\n const mls = this.#mls;\r\n const payload =\r\n signalCsv && signalCsv.length > 0 ? (0,_utils__WEBPACK_IMPORTED_MODULE_2__.csvToArray)(signalCsv) : allSignals[numSignals - 1];\r\n\r\n this.emit('update', {message: `computing the IR of the last recording...`});\r\n this.impulseResponses.push(\r\n this.pyServerAPI\r\n .getImpulseResponse({\r\n sampleRate: this.sourceSamplingRate || 96000,\r\n payload,\r\n mls,\r\n P: this.#P,\r\n })\r\n .then(res => {\r\n if (this.numSuccessfulCaptured < this.numCaptures) {\r\n this.numSuccessfulCaptured += 1;\r\n console.log(\"num succ capt: \" + this.numSuccessfulCaptured);\r\n this.emit('update', {\r\n message: `${this.numSuccessfulCaptured}/${this.numCaptures} IRs computed...`,\r\n });\r\n }\r\n return res;\r\n })\r\n .catch(err => {\r\n console.error(err);\r\n })\r\n );\r\n };\r\n\r\n /**\r\n * Passed to the calibration steps function, awaits the desired amount of seconds to capture the desired number\r\n * of MLS periods defined in the constructor.\r\n *\r\n * @example\r\n */\r\n #awaitDesiredMLSLength = async () => {\r\n // seconds per MLS = P / SR\r\n // await N * P / SR\r\n this.emit('update', {\r\n message: `sampling the calibration signal...`,\r\n });\r\n await (0,_utils__WEBPACK_IMPORTED_MODULE_2__.sleep)((this.#P / this.sourceSamplingRate) * this.numMLSPerCapture);\r\n };\r\n\r\n /** .\r\n * .\r\n * .\r\n * Passed to the calibration steps function, awaits the onset of the signal to ensure a steady state\r\n *\r\n * @example\r\n */\r\n #awaitSignalOnset = async () => {\r\n this.emit('update', {\r\n message: `waiting for the signal to stabalize...`,\r\n });\r\n await (0,_utils__WEBPACK_IMPORTED_MODULE_2__.sleep)(this.TAPER_SECS);\r\n };\r\n\r\n /**\r\n * Called immediately after a recording is captured. Used to process the resulting signal\r\n * whether by sending the result to a server or by computing a result locally.\r\n *\r\n * @example\r\n */\r\n #afterMLSRecord = () => {\r\n if (this.#download) {\r\n this.downloadData();\r\n }\r\n this.sendRecordingToServerForProcessing();\r\n };\r\n\r\n #afterMLSwIIRRecord = () => {\r\n if (this.#download) {\r\n this.downloadConvolvedData();\r\n }\r\n if (this.numSuccessfulCaptured < this.numCaptures) {\r\n this.numSuccessfulCaptured += 1;\r\n this.emit('update', {\r\n message: `${this.numSuccessfulCaptured}/${this.numCaptures} IRs computed...`,\r\n });\r\n }\r\n };\r\n\r\n /** .\r\n * .\r\n * .\r\n * Created an S Curver Buffer to taper the signal onset\r\n *\r\n * @param {*} length\r\n * @param {*} phase\r\n * @returns\r\n * @example\r\n */\r\n static createSCurveBuffer = (length, phase) => {\r\n const curve = new Float32Array(length);\r\n let i;\r\n for (i = 0; i < length; i += 1) {\r\n // scale the curve to be between 0-1\r\n curve[i] = Math.sin((Math.PI * i) / length - phase) / 2 + 0.5;\r\n }\r\n return curve;\r\n };\r\n\r\n static createInverseSCurveBuffer = (length, phase) => {\r\n const curve = new Float32Array(length);\r\n let i;\r\n let j = length - 1;\r\n for (i = 0; i < length; i += 1) {\r\n // scale the curve to be between 0-1\r\n curve[i] = Math.sin((Math.PI * j) / length - phase) / 2 + 0.5;\r\n j -= 1;\r\n }\r\n return curve;\r\n };\r\n\r\n /**\r\n * Construct a Calibration Node with the calibration parameters.\r\n *\r\n * @param CALIBRATION_TONE_FREQUENCY\r\n * @private\r\n * @example\r\n */\r\n #createPureTonenNode = CALIBRATION_TONE_FREQUENCY => {\r\n const audioContext = this.makeNewSourceAudioContext();\r\n const oscilator = audioContext.createOscillator();\r\n const gainNode = audioContext.createGain();\r\n\r\n oscilator.frequency.value = CALIBRATION_TONE_FREQUENCY;\r\n oscilator.type = 'sine';\r\n gainNode.gain.value = 0.04;\r\n\r\n oscilator.connect(gainNode);\r\n gainNode.connect(audioContext.destination);\r\n\r\n this.addCalibrationNode(oscilator);\r\n };\r\n\r\n /**\r\n * Construct a Calibration Node with the calibration parameters.\r\n *\r\n * @param dataBuffer\r\n * @private\r\n * @example\r\n */\r\n #createCalibrationNodeFromBuffer = dataBuffer => {\r\n const audioContext = this.makeNewSourceAudioContext();\r\n const buffer = audioContext.createBuffer(\r\n 1, // number of channels\r\n dataBuffer.length,\r\n audioContext.sampleRate // sample rate\r\n );\r\n\r\n const data = buffer.getChannelData(0); // get data\r\n // fill the buffer with our data\r\n try {\r\n for (let i = 0; i < dataBuffer.length; i += 1) {\r\n data[i] = dataBuffer[i]*.1;\r\n }\r\n } catch (error) {\r\n console.error(error);\r\n }\r\n console.log(\"mls second, same?\");\r\n console.log(data);\r\n const onsetGainNode = audioContext.createGain();\r\n this.offsetGainNode = audioContext.createGain();\r\n const source = audioContext.createBufferSource();\r\n\r\n source.buffer = buffer;\r\n source.loop = true;\r\n source.connect(onsetGainNode);\r\n onsetGainNode.connect(this.offsetGainNode);\r\n this.offsetGainNode.connect(audioContext.destination);\r\n\r\n const onsetCurve = ImpulseResponse.createSCurveBuffer(this.sourceSamplingRate, Math.PI / 2);\r\n onsetGainNode.gain.setValueCurveAtTime(onsetCurve, 0, this.TAPER_SECS);\r\n this.addCalibrationNode(source);\r\n };\r\n\r\n /**\r\n * Given a data buffer, creates the required calibration node\r\n *\r\n * @param {*} dataBufferArray\r\n * @example\r\n */\r\n #setCalibrationNodesFromBuffer = (dataBufferArray = [this.#mlsBufferView]) => {\r\n if (dataBufferArray.length === 1) {\r\n console.log('data buffer aray');\r\n console.log(dataBufferArray);\r\n this.#createCalibrationNodeFromBuffer(dataBufferArray[0]);\r\n } else {\r\n throw new Error('The length of the data buffer array must be 1');\r\n }\r\n\r\n \r\n };\r\n\r\n /**\r\n * function to put MLS filtered IIR data obtained from\r\n * python server into our audio buffer to be played aloud\r\n */\r\n #putInPythonConv = () => {\r\n const audioCtx = this.makeNewSourceAudioContextConvolved();\r\n const buffer = audioCtx.createBuffer(\r\n 1, // number of channels\r\n this.convolution.length,\r\n audioCtx.sampleRate // sample rate\r\n );\r\n\r\n const data = buffer.getChannelData(0); // get data\r\n // fill the buffer with our data\r\n try {\r\n for (let i = 0; i < this.convolution.length; i += 1) {\r\n data[i] = this.convolution[i];\r\n }\r\n } catch (error) {\r\n console.error(error);\r\n }\r\n\r\n const source = audioCtx.createBufferSource();\r\n\r\n source.buffer = buffer;\r\n source.loop = true;\r\n source.connect(audioCtx.destination);\r\n\r\n this.addCalibrationNodeConvolved(source);\r\n }\r\n \r\n /**\r\n * Creates an audio context and plays it for a few seconds.\r\n *\r\n * @private\r\n * @returns - Resolves when the audio is done playing.\r\n * @example\r\n */\r\n #playCalibrationAudio = () => {\r\n this.calibrationNodes[0].start(0);\r\n this.#mls = this.calibrationNodes[0].buffer.getChannelData(0);\r\n console.log(this.#mls);\r\n this.emit('update', {message: 'playing the calibration tone...'});\r\n }; \r\n\r\n\r\n #playCalibrationAudioConvolved = () => {\r\n this.calibrationNodesConvolved[0].start(0);\r\n this.emit('update',{message: 'playing the convolved calibration tone...'})\r\n }\r\n\r\n /** .\r\n * .\r\n * .\r\n * Stops the audio with tapered offset\r\n *\r\n * @example\r\n */\r\n #stopCalibrationAudio = () => {\r\n this.offsetGainNode.gain.setValueAtTime(\r\n this.offsetGainNode.gain.value,\r\n this.sourceAudioContext.currentTime\r\n );\r\n\r\n this.offsetGainNode.gain.setTargetAtTime(0, this.sourceAudioContext.currentTime, 0.5);\r\n this.calibrationNodes[0].stop(0);\r\n this.sourceAudioContext.close();\r\n this.emit('update', {message: 'stopping the calibration tone...'});\r\n };\r\n\r\n #stopCalibrationAudioConvolved = () => {\r\n this.offsetGainNode.gain.setValueAtTime(\r\n this.offsetGainNode.gain.value,\r\n this.sourceAudioContextConvolved.currentTime\r\n );\r\n\r\n this.offsetGainNode.gain.setTargetAtTime(0, this.sourceAudioContextConvolved.currentTime, 0.5);\r\n //this.calibrationNodesConvolved[0].stop(0);\r\n console.log(\"right before closing volved audio context\");\r\n this.sourceAudioContextConvolved.close();\r\n this.emit('update', {message: 'stopping the convolved calibration tone...'});\r\n\r\n }\r\n\r\n playMLSwithIIR = async (stream, iir) => {\r\n console.log('play mls with iir');\r\n this.invertedImpulseResponse = iir;\r\n // initialize the MLSGenInterface object with it's factory method\r\n \r\n await _mlsGen_mlsGenInterface__WEBPACK_IMPORTED_MODULE_1__[\"default\"].factory(\r\n this.#mlsOrder,\r\n this.sinkSamplingRate,\r\n this.sourceSamplingRate\r\n ).then(mlsGenInterface => {\r\n this.#mlsGenInterface = mlsGenInterface;\r\n this.#mlsBufferView = this.#mlsGenInterface.getMLS();\r\n });\r\n\r\n console.log('after mls factory'); //works up to here.\r\n console.log(this.#mls);\r\n // after intializating, start the calibration steps with garbage collection\r\n await this.#mlsGenInterface.withGarbageCollection([\r\n () =>\r\n this.calibrationSteps(\r\n stream,\r\n this.#playCalibrationAudioConvolved, // play audio func (required)\r\n this.#putInPythonConv, // before play func\r\n this.#awaitSignalOnset, // before record\r\n () => this.numSuccessfulCaptured < this.numCaptures,\r\n this.#awaitDesiredMLSLength, // during record\r\n this.#afterMLSwIIRRecord, // after record\r\n ),\r\n ]);\r\n };\r\n\r\n /**\r\n * Public method to start the calibration process. Objects intialized from webassembly allocate new memory\r\n * and must be manually freed. This function is responsible for intializing the MlsGenInterface,\r\n * and wrapping the calibration steps with a garbage collection safe gaurd.\r\n *\r\n * @public\r\n * @param stream - The stream of audio from the Listener.\r\n * @example\r\n */\r\n startCalibration = async stream => {\r\n // initialize the MLSGenInterface object with it's factory method\r\n await _mlsGen_mlsGenInterface__WEBPACK_IMPORTED_MODULE_1__[\"default\"].factory(\r\n this.#mlsOrder,\r\n this.sinkSamplingRate,\r\n this.sourceSamplingRate\r\n ).then(mlsGenInterface => {\r\n this.#mlsGenInterface = mlsGenInterface;\r\n this.#mlsBufferView = this.#mlsGenInterface.getMLS();\r\n });\r\n\r\n // after intializating, start the calibration steps with garbage collection\r\n await this.#mlsGenInterface.withGarbageCollection([\r\n () =>\r\n this.calibrationSteps(\r\n stream,\r\n this.#playCalibrationAudio, // play audio func (required)\r\n this.#setCalibrationNodesFromBuffer, // before play func\r\n this.#awaitSignalOnset, // before record\r\n () => this.numSuccessfulCaptured < this.numCaptures, // loop while true\r\n this.#awaitDesiredMLSLength, // during record\r\n this.#afterMLSRecord // after record\r\n ),\r\n ]);\r\n\r\n this.#stopCalibrationAudio();\r\n\r\n // at this stage we've captured all the required signals,\r\n // and have received IRs for each one\r\n // so let's send all the IRs to the server to be converted to a single IIR\r\n await this.sendImpulseResponsesToServerForProcessing();\r\n\r\n if (this.#download) {\r\n (0,_utils__WEBPACK_IMPORTED_MODULE_2__.saveToCSV)(this.invertedImpulseResponse,'IIR.csv');\r\n const computedIRagain = await Promise.all(this.impulseResponses)\r\n .then(res => {\r\n for (let i = 0; i < res.length; i++){\r\n (0,_utils__WEBPACK_IMPORTED_MODULE_2__.saveToCSV)(res[i], `IR_${i}`);\r\n }\r\n })\r\n ;(0,_utils__WEBPACK_IMPORTED_MODULE_2__.saveToCSV)(this.#mls,\"MLS.csv\");\r\n (0,_utils__WEBPACK_IMPORTED_MODULE_2__.saveToCSV)(this.convolution,'python_convolution_mls_iir.csv');\r\n }\r\n\r\n this.numSuccessfulCaptured = 0;\r\n // debugging function, use to test the result of the IIR\r\n await this.playMLSwithIIR(stream, this.invertedImpulseResponse);\r\n this.#stopCalibrationAudioConvolved();\r\n\r\n return this.invertedImpulseResponse;\r\n };\r\n}\r\n\r\n/* harmony default export */ __webpack_exports__[\"default\"] = (ImpulseResponse);\r\n\n\n//# sourceURL=webpack://speakerCalibrator/./src/tasks/impulse-response/impulseResponse.js?");
|
|
799
|
+
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _audioCalibrator__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../audioCalibrator */ \"./src/tasks/audioCalibrator.js\");\n/* harmony import */ var _mlsGen_mlsGenInterface__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./mlsGen/mlsGenInterface */ \"./src/tasks/impulse-response/mlsGen/mlsGenInterface.js\");\n/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../utils */ \"./src/utils.js\");\n\r\n\r\n\r\n\r\n\r\n/**\r\n *\r\n */\r\nclass ImpulseResponse extends _audioCalibrator__WEBPACK_IMPORTED_MODULE_0__[\"default\"] {\r\n /**\r\n * Default constructor. Creates an instance with any number of paramters passed or the default parameters defined here.\r\n *\r\n * @param {Object<boolean, number, number, number>} calibratorParams - paramter object\r\n * @param {boolean} [calibratorParams.download = false] - boolean flag to download captures\r\n * @param {number} [calibratorParams.mlsOrder = 18] - order of the MLS to be generated\r\n * @param {number} [calibratorParams.numCaptures = 5] - number of captures to perform\r\n * @param {number} [calibratorParams.numMLSPerCapture = 4] - number of bursts of MLS per capture\r\n */\r\n constructor({download = false, mlsOrder = 18, numCaptures = 3, numMLSPerCapture = 4, lowHz = 20, highHz = 10000}) {\r\n super(numCaptures, numMLSPerCapture);\r\n this.#mlsOrder = parseInt(mlsOrder, 10);\r\n this.#P = 2 ** mlsOrder - 1;\r\n this.#download = download;\r\n this.#mls = [];\r\n this.#lowHz = lowHz;\r\n this.#highHz = highHz;\r\n }\r\n\r\n /** @private */\r\n #download;\r\n\r\n /** @private */\r\n #mlsGenInterface;\r\n\r\n /** @private */\r\n #mlsBufferView;\r\n\r\n /** @private */\r\n invertedImpulseResponse = null;\r\n\r\n /** @private */\r\n impulseResponses = [];\r\n\r\n /** @private */\r\n #mlsOrder;\r\n\r\n /** @private */\r\n #lowHz;\r\n\r\n /** @private */\r\n #highHz;\r\n\r\n /** @private */\r\n #mls;\r\n\r\n /** @private */\r\n #P;\r\n\r\n /** @private */\r\n #audioContext;\r\n\r\n /** @private */\r\n TAPER_SECS = 5;\r\n\r\n /** @private */\r\n offsetGainNode;\r\n\r\n /** @private */\r\n convolution;\r\n\r\n /** .\r\n * .\r\n * .\r\n * Sends all the computed impulse responses to the backend server for processing\r\n *\r\n * @returns sets the resulting inverted impulse response to the class property\r\n * @example\r\n */\r\n sendImpulseResponsesToServerForProcessing = async () => {\r\n const computedIRs = await Promise.all(this.impulseResponses);\r\n const mls = this.#mls;\r\n const lowHz = this.#lowHz;\r\n const highHz = this.#highHz;\r\n this.emit('update', {message: `computing the IIR...`});\r\n return this.pyServerAPI\r\n .getInverseImpulseResponse({\r\n payload: computedIRs.slice(0, this.numCaptures),\r\n mls,\r\n lowHz,\r\n highHz\r\n })\r\n .then(res => {\r\n console.log(res);\r\n this.emit('update', {message: `done computing the IIR...`});\r\n this.invertedImpulseResponse = res[\"iir\"];\r\n this.convolution = res[\"convolution\"];\r\n })\r\n .catch(err => {\r\n // this.emit('InvertedImpulseResponse', {res: false});\r\n console.error(err);\r\n });\r\n };\r\n\r\n /** .\r\n * .\r\n * .\r\n * Sends the recorded signal, or a given csv string of a signal, to the back end server for processing\r\n *\r\n * @param {<array>String} signalCsv - Optional csv string of a previously recorded signal, if given, this signal will be processed\r\n * @example\r\n */\r\n sendRecordingToServerForProcessing = signalCsv => {\r\n const allSignals = this.getAllRecordedSignals();\r\n const numSignals = allSignals.length;\r\n const mls = this.#mls;\r\n const payload =\r\n signalCsv && signalCsv.length > 0 ? (0,_utils__WEBPACK_IMPORTED_MODULE_2__.csvToArray)(signalCsv) : allSignals[numSignals - 1];\r\n\r\n this.emit('update', {message: `computing the IR of the last recording...`});\r\n this.impulseResponses.push(\r\n this.pyServerAPI\r\n .getImpulseResponse({\r\n sampleRate: this.sourceSamplingRate || 96000,\r\n payload,\r\n mls,\r\n P: this.#P,\r\n })\r\n .then(res => {\r\n if (this.numSuccessfulCaptured < this.numCaptures) {\r\n this.numSuccessfulCaptured += 1;\r\n console.log(\"num succ capt: \" + this.numSuccessfulCaptured);\r\n this.emit('update', {\r\n message: `${this.numSuccessfulCaptured}/${this.numCaptures} IRs computed...`,\r\n });\r\n }\r\n return res;\r\n })\r\n .catch(err => {\r\n console.error(err);\r\n })\r\n );\r\n };\r\n\r\n /**\r\n * Passed to the calibration steps function, awaits the desired amount of seconds to capture the desired number\r\n * of MLS periods defined in the constructor.\r\n *\r\n * @example\r\n */\r\n #awaitDesiredMLSLength = async () => {\r\n // seconds per MLS = P / SR\r\n // await N * P / SR\r\n this.emit('update', {\r\n message: `sampling the calibration signal...`,\r\n });\r\n await (0,_utils__WEBPACK_IMPORTED_MODULE_2__.sleep)((this.#P / this.sourceSamplingRate) * this.numMLSPerCapture);\r\n };\r\n\r\n /** .\r\n * .\r\n * .\r\n * Passed to the calibration steps function, awaits the onset of the signal to ensure a steady state\r\n *\r\n * @example\r\n */\r\n #awaitSignalOnset = async () => {\r\n this.emit('update', {\r\n message: `waiting for the signal to stabalize...`,\r\n });\r\n await (0,_utils__WEBPACK_IMPORTED_MODULE_2__.sleep)(this.TAPER_SECS);\r\n };\r\n\r\n /**\r\n * Called immediately after a recording is captured. Used to process the resulting signal\r\n * whether by sending the result to a server or by computing a result locally.\r\n *\r\n * @example\r\n */\r\n #afterMLSRecord = () => {\r\n if (this.#download) {\r\n this.downloadData();\r\n }\r\n this.sendRecordingToServerForProcessing();\r\n };\r\n\r\n #afterMLSwIIRRecord = () => {\r\n if (this.#download) {\r\n this.downloadConvolvedData();\r\n }\r\n if (this.numSuccessfulCaptured < this.numCaptures) {\r\n this.numSuccessfulCaptured += 1;\r\n this.emit('update', {\r\n message: `${this.numSuccessfulCaptured}/${this.numCaptures} IRs computed...`,\r\n });\r\n }\r\n };\r\n\r\n /** .\r\n * .\r\n * .\r\n * Created an S Curver Buffer to taper the signal onset\r\n *\r\n * @param {*} length\r\n * @param {*} phase\r\n * @returns\r\n * @example\r\n */\r\n static createSCurveBuffer = (length, phase) => {\r\n const curve = new Float32Array(length);\r\n let i;\r\n for (i = 0; i < length; i += 1) {\r\n // scale the curve to be between 0-1\r\n curve[i] = Math.sin((Math.PI * i) / length - phase) / 2 + 0.5;\r\n }\r\n return curve;\r\n };\r\n\r\n static createInverseSCurveBuffer = (length, phase) => {\r\n const curve = new Float32Array(length);\r\n let i;\r\n let j = length - 1;\r\n for (i = 0; i < length; i += 1) {\r\n // scale the curve to be between 0-1\r\n curve[i] = Math.sin((Math.PI * j) / length - phase) / 2 + 0.5;\r\n j -= 1;\r\n }\r\n return curve;\r\n };\r\n\r\n /**\r\n * Construct a Calibration Node with the calibration parameters.\r\n *\r\n * @param CALIBRATION_TONE_FREQUENCY\r\n * @private\r\n * @example\r\n */\r\n #createPureTonenNode = CALIBRATION_TONE_FREQUENCY => {\r\n const audioContext = this.makeNewSourceAudioContext();\r\n const oscilator = audioContext.createOscillator();\r\n const gainNode = audioContext.createGain();\r\n\r\n oscilator.frequency.value = CALIBRATION_TONE_FREQUENCY;\r\n oscilator.type = 'sine';\r\n gainNode.gain.value = 0.04;\r\n\r\n oscilator.connect(gainNode);\r\n gainNode.connect(audioContext.destination);\r\n\r\n this.addCalibrationNode(oscilator);\r\n };\r\n\r\n /**\r\n * Construct a Calibration Node with the calibration parameters.\r\n *\r\n * @param dataBuffer\r\n * @private\r\n * @example\r\n */\r\n #createCalibrationNodeFromBuffer = dataBuffer => {\r\n const audioContext = this.makeNewSourceAudioContext();\r\n const buffer = audioContext.createBuffer(\r\n 1, // number of channels\r\n dataBuffer.length,\r\n audioContext.sampleRate // sample rate\r\n );\r\n\r\n const data = buffer.getChannelData(0); // get data\r\n // fill the buffer with our data\r\n try {\r\n for (let i = 0; i < dataBuffer.length; i += 1) {\r\n data[i] = dataBuffer[i]*.1;\r\n }\r\n } catch (error) {\r\n console.error(error);\r\n }\r\n console.log(\"mls second, same?\");\r\n console.log(data);\r\n const onsetGainNode = audioContext.createGain();\r\n this.offsetGainNode = audioContext.createGain();\r\n const source = audioContext.createBufferSource();\r\n\r\n source.buffer = buffer;\r\n source.loop = true;\r\n source.connect(onsetGainNode);\r\n onsetGainNode.connect(this.offsetGainNode);\r\n this.offsetGainNode.connect(audioContext.destination);\r\n\r\n const onsetCurve = ImpulseResponse.createSCurveBuffer(this.sourceSamplingRate, Math.PI / 2);\r\n onsetGainNode.gain.setValueCurveAtTime(onsetCurve, 0, this.TAPER_SECS);\r\n this.addCalibrationNode(source);\r\n };\r\n\r\n /**\r\n * Given a data buffer, creates the required calibration node\r\n *\r\n * @param {*} dataBufferArray\r\n * @example\r\n */\r\n #setCalibrationNodesFromBuffer = (dataBufferArray = [this.#mlsBufferView]) => {\r\n if (dataBufferArray.length === 1) {\r\n console.log('data buffer aray');\r\n console.log(dataBufferArray);\r\n this.#createCalibrationNodeFromBuffer(dataBufferArray[0]);\r\n } else {\r\n throw new Error('The length of the data buffer array must be 1');\r\n }\r\n\r\n \r\n };\r\n\r\n /**\r\n * function to put MLS filtered IIR data obtained from\r\n * python server into our audio buffer to be played aloud\r\n */\r\n #putInPythonConv = () => {\r\n const audioCtx = this.makeNewSourceAudioContextConvolved();\r\n const buffer = audioCtx.createBuffer(\r\n 1, // number of channels\r\n this.convolution.length,\r\n audioCtx.sampleRate // sample rate\r\n );\r\n\r\n const data = buffer.getChannelData(0); // get data\r\n // fill the buffer with our data\r\n try {\r\n for (let i = 0; i < this.convolution.length; i += 1) {\r\n data[i] = this.convolution[i];\r\n }\r\n } catch (error) {\r\n console.error(error);\r\n }\r\n\r\n const source = audioCtx.createBufferSource();\r\n\r\n source.buffer = buffer;\r\n source.loop = true;\r\n source.connect(audioCtx.destination);\r\n\r\n this.addCalibrationNodeConvolved(source);\r\n }\r\n \r\n /**\r\n * Creates an audio context and plays it for a few seconds.\r\n *\r\n * @private\r\n * @returns - Resolves when the audio is done playing.\r\n * @example\r\n */\r\n #playCalibrationAudio = () => {\r\n this.calibrationNodes[0].start(0);\r\n this.#mls = this.calibrationNodes[0].buffer.getChannelData(0);\r\n console.log(this.#mls);\r\n this.emit('update', {message: 'playing the calibration tone...'});\r\n }; \r\n\r\n\r\n #playCalibrationAudioConvolved = () => {\r\n this.calibrationNodesConvolved[0].start(0);\r\n this.emit('update',{message: 'playing the convolved calibration tone...'})\r\n }\r\n\r\n /** .\r\n * .\r\n * .\r\n * Stops the audio with tapered offset\r\n *\r\n * @example\r\n */\r\n #stopCalibrationAudio = () => {\r\n this.offsetGainNode.gain.setValueAtTime(\r\n this.offsetGainNode.gain.value,\r\n this.sourceAudioContext.currentTime\r\n );\r\n\r\n this.offsetGainNode.gain.setTargetAtTime(0, this.sourceAudioContext.currentTime, 0.5);\r\n this.calibrationNodes[0].stop(0);\r\n this.sourceAudioContext.close();\r\n this.emit('update', {message: 'stopping the calibration tone...'});\r\n };\r\n\r\n #stopCalibrationAudioConvolved = () => {\r\n this.offsetGainNode.gain.setValueAtTime(\r\n this.offsetGainNode.gain.value,\r\n this.sourceAudioContextConvolved.currentTime\r\n );\r\n\r\n this.offsetGainNode.gain.setTargetAtTime(0, this.sourceAudioContextConvolved.currentTime, 0.5);\r\n //this.calibrationNodesConvolved[0].stop(0);\r\n console.log(\"right before closing volved audio context\");\r\n this.sourceAudioContextConvolved.close();\r\n this.emit('update', {message: 'stopping the convolved calibration tone...'});\r\n\r\n }\r\n\r\n playMLSwithIIR = async (stream, iir) => {\r\n console.log('play mls with iir');\r\n this.invertedImpulseResponse = iir;\r\n // initialize the MLSGenInterface object with it's factory method\r\n \r\n await _mlsGen_mlsGenInterface__WEBPACK_IMPORTED_MODULE_1__[\"default\"].factory(\r\n this.#mlsOrder,\r\n this.sinkSamplingRate,\r\n this.sourceSamplingRate\r\n ).then(mlsGenInterface => {\r\n this.#mlsGenInterface = mlsGenInterface;\r\n this.#mlsBufferView = this.#mlsGenInterface.getMLS();\r\n });\r\n\r\n console.log('after mls factory'); //works up to here.\r\n console.log(this.#mls);\r\n // after intializating, start the calibration steps with garbage collection\r\n await this.#mlsGenInterface.withGarbageCollection([\r\n () =>\r\n this.calibrationSteps(\r\n stream,\r\n this.#playCalibrationAudioConvolved, // play audio func (required)\r\n this.#putInPythonConv, // before play func\r\n this.#awaitSignalOnset, // before record\r\n () => this.numSuccessfulCaptured < this.numCaptures,\r\n this.#awaitDesiredMLSLength, // during record\r\n this.#afterMLSwIIRRecord, // after record\r\n ),\r\n ]);\r\n };\r\n\r\n /**\r\n * Public method to start the calibration process. Objects intialized from webassembly allocate new memory\r\n * and must be manually freed. This function is responsible for intializing the MlsGenInterface,\r\n * and wrapping the calibration steps with a garbage collection safe gaurd.\r\n *\r\n * @public\r\n * @param stream - The stream of audio from the Listener.\r\n * @example\r\n */\r\n startCalibration = async stream => {\r\n // initialize the MLSGenInterface object with it's factory method\r\n await _mlsGen_mlsGenInterface__WEBPACK_IMPORTED_MODULE_1__[\"default\"].factory(\r\n this.#mlsOrder,\r\n this.sinkSamplingRate,\r\n this.sourceSamplingRate\r\n ).then(mlsGenInterface => {\r\n this.#mlsGenInterface = mlsGenInterface;\r\n this.#mlsBufferView = this.#mlsGenInterface.getMLS();\r\n });\r\n\r\n // after intializating, start the calibration steps with garbage collection\r\n await this.#mlsGenInterface.withGarbageCollection([\r\n () =>\r\n this.calibrationSteps(\r\n stream,\r\n this.#playCalibrationAudio, // play audio func (required)\r\n this.#setCalibrationNodesFromBuffer, // before play func\r\n this.#awaitSignalOnset, // before record\r\n () => this.numSuccessfulCaptured < this.numCaptures, // loop while true\r\n this.#awaitDesiredMLSLength, // during record\r\n this.#afterMLSRecord // after record\r\n ),\r\n ]);\r\n\r\n this.#stopCalibrationAudio();\r\n\r\n // at this stage we've captured all the required signals,\r\n // and have received IRs for each one\r\n // so let's send all the IRs to the server to be converted to a single IIR\r\n await this.sendImpulseResponsesToServerForProcessing();\r\n\r\n if (this.#download) {\r\n (0,_utils__WEBPACK_IMPORTED_MODULE_2__.saveToCSV)(this.invertedImpulseResponse,'IIR.csv');\r\n const computedIRagain = await Promise.all(this.impulseResponses)\r\n .then(res => {\r\n for (let i = 0; i < res.length; i++){\r\n (0,_utils__WEBPACK_IMPORTED_MODULE_2__.saveToCSV)(res[i], `IR_${i}`);\r\n }\r\n })\r\n ;(0,_utils__WEBPACK_IMPORTED_MODULE_2__.saveToCSV)(this.#mls,\"MLS.csv\");\r\n (0,_utils__WEBPACK_IMPORTED_MODULE_2__.saveToCSV)(this.convolution,'python_convolution_mls_iir.csv');\r\n }\r\n\r\n this.numSuccessfulCaptured = 0;\r\n // debugging function, use to test the result of the IIR\r\n await this.playMLSwithIIR(stream, this.invertedImpulseResponse);\r\n this.#stopCalibrationAudioConvolved();\r\n\r\n let recs = this.getAllRecordedSignals();\r\n let unconv_rec = recs[0];\r\n let conv_rec = recs[4];\r\n\r\n let results = await this.pyServerAPI\r\n .getPSD({\r\n unconv_rec,\r\n conv_rec,\r\n })\r\n .then(res => {\r\n return res;\r\n })\r\n .catch(err => {\r\n console.error(err);\r\n })\r\n\r\n let iir_and_plots = {\r\n \"iir\": this.invertedImpulseResponse,\r\n \"x_unconv\": results[\"x_unconv\"],\r\n \"y_unconv\": results[\"y_unconv\"],\r\n \"x_conv\": results[\"x_conv\"],\r\n \"y_conv\": results[\"y_conv\"]\r\n }\r\n\r\n return iir_and_plots;\r\n };\r\n}\r\n\r\n/* harmony default export */ __webpack_exports__[\"default\"] = (ImpulseResponse);\r\n\n\n//# sourceURL=webpack://speakerCalibrator/./src/tasks/impulse-response/impulseResponse.js?");
|
|
800
800
|
|
|
801
801
|
/***/ }),
|
|
802
802
|
|
package/package.json
CHANGED
|
@@ -26,6 +26,12 @@ class ImpulseResponse extends AudioCalibrator {
|
|
|
26
26
|
this.#highHz = highHz;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
/** @private */
|
|
30
|
+
stepNum = 0;
|
|
31
|
+
|
|
32
|
+
/** @private */
|
|
33
|
+
totalSteps = 25;
|
|
34
|
+
|
|
29
35
|
/** @private */
|
|
30
36
|
#download;
|
|
31
37
|
|
|
@@ -81,7 +87,8 @@ class ImpulseResponse extends AudioCalibrator {
|
|
|
81
87
|
const mls = this.#mls;
|
|
82
88
|
const lowHz = this.#lowHz;
|
|
83
89
|
const highHz = this.#highHz;
|
|
84
|
-
this.
|
|
90
|
+
this.stepNum += 1;
|
|
91
|
+
this.emit('update', {message: `Step ${this.stepNum}/${this.totalSteps}: computing the IIR...`});
|
|
85
92
|
return this.pyServerAPI
|
|
86
93
|
.getInverseImpulseResponse({
|
|
87
94
|
payload: computedIRs.slice(0, this.numCaptures),
|
|
@@ -91,7 +98,8 @@ class ImpulseResponse extends AudioCalibrator {
|
|
|
91
98
|
})
|
|
92
99
|
.then(res => {
|
|
93
100
|
console.log(res);
|
|
94
|
-
this.
|
|
101
|
+
this.stepNum += 1;
|
|
102
|
+
this.emit('update', {message: `Step ${this.stepNum}/${this.totalSteps}: done computing the IIR...`});
|
|
95
103
|
this.invertedImpulseResponse = res["iir"];
|
|
96
104
|
this.convolution = res["convolution"];
|
|
97
105
|
})
|
|
@@ -115,8 +123,9 @@ class ImpulseResponse extends AudioCalibrator {
|
|
|
115
123
|
const mls = this.#mls;
|
|
116
124
|
const payload =
|
|
117
125
|
signalCsv && signalCsv.length > 0 ? csvToArray(signalCsv) : allSignals[numSignals - 1];
|
|
118
|
-
|
|
119
|
-
this.
|
|
126
|
+
console.log('sending rec');
|
|
127
|
+
this.stepNum += 1;
|
|
128
|
+
this.emit('update', {message: `Step: ${this.stepNum}/${this.totalSteps}: computing the IR of the last recording...`});
|
|
120
129
|
this.impulseResponses.push(
|
|
121
130
|
this.pyServerAPI
|
|
122
131
|
.getImpulseResponse({
|
|
@@ -129,8 +138,9 @@ class ImpulseResponse extends AudioCalibrator {
|
|
|
129
138
|
if (this.numSuccessfulCaptured < this.numCaptures) {
|
|
130
139
|
this.numSuccessfulCaptured += 1;
|
|
131
140
|
console.log("num succ capt: " + this.numSuccessfulCaptured);
|
|
141
|
+
this.stepNum += 1;
|
|
132
142
|
this.emit('update', {
|
|
133
|
-
message:
|
|
143
|
+
message: `Step: ${this.stepNum}/${this.totalSteps}: ${this.numSuccessfulCaptured}/${this.numCaptures} IRs computed...`,
|
|
134
144
|
});
|
|
135
145
|
}
|
|
136
146
|
return res;
|
|
@@ -150,8 +160,9 @@ class ImpulseResponse extends AudioCalibrator {
|
|
|
150
160
|
#awaitDesiredMLSLength = async () => {
|
|
151
161
|
// seconds per MLS = P / SR
|
|
152
162
|
// await N * P / SR
|
|
163
|
+
this.stepNum += 1;
|
|
153
164
|
this.emit('update', {
|
|
154
|
-
message: `sampling the calibration signal...`,
|
|
165
|
+
message: `Step ${this.stepNum}/${this.totalSteps}: sampling the calibration signal...`,
|
|
155
166
|
});
|
|
156
167
|
await sleep((this.#P / this.sourceSamplingRate) * this.numMLSPerCapture);
|
|
157
168
|
};
|
|
@@ -164,8 +175,9 @@ class ImpulseResponse extends AudioCalibrator {
|
|
|
164
175
|
* @example
|
|
165
176
|
*/
|
|
166
177
|
#awaitSignalOnset = async () => {
|
|
178
|
+
this.stepNum += 1;
|
|
167
179
|
this.emit('update', {
|
|
168
|
-
message: `waiting for the signal to
|
|
180
|
+
message: `Step ${this.stepNum}/${this.totalSteps}: waiting for the signal to stabilize...`,
|
|
169
181
|
});
|
|
170
182
|
await sleep(this.TAPER_SECS);
|
|
171
183
|
};
|
|
@@ -180,6 +192,7 @@ class ImpulseResponse extends AudioCalibrator {
|
|
|
180
192
|
if (this.#download) {
|
|
181
193
|
this.downloadData();
|
|
182
194
|
}
|
|
195
|
+
console.log('after record');
|
|
183
196
|
this.sendRecordingToServerForProcessing();
|
|
184
197
|
};
|
|
185
198
|
|
|
@@ -189,8 +202,9 @@ class ImpulseResponse extends AudioCalibrator {
|
|
|
189
202
|
}
|
|
190
203
|
if (this.numSuccessfulCaptured < this.numCaptures) {
|
|
191
204
|
this.numSuccessfulCaptured += 1;
|
|
205
|
+
this.stepNum += 1;
|
|
192
206
|
this.emit('update', {
|
|
193
|
-
message:
|
|
207
|
+
message: `Step ${this.stepNum}/${this.totalSteps}: ${this.numSuccessfulCaptured} recordings of convolved MLS captured`,
|
|
194
208
|
});
|
|
195
209
|
}
|
|
196
210
|
};
|
|
@@ -349,14 +363,15 @@ class ImpulseResponse extends AudioCalibrator {
|
|
|
349
363
|
#playCalibrationAudio = () => {
|
|
350
364
|
this.calibrationNodes[0].start(0);
|
|
351
365
|
this.#mls = this.calibrationNodes[0].buffer.getChannelData(0);
|
|
352
|
-
|
|
353
|
-
this.emit('update', {message:
|
|
366
|
+
this.stepNum += 1;
|
|
367
|
+
this.emit('update', {message: `Step: ${this.stepNum}/${this.totalSteps}: playing the calibration tone...`});
|
|
354
368
|
};
|
|
355
369
|
|
|
356
370
|
|
|
357
371
|
#playCalibrationAudioConvolved = () => {
|
|
358
372
|
this.calibrationNodesConvolved[0].start(0);
|
|
359
|
-
this.
|
|
373
|
+
this.stepNum += 1;
|
|
374
|
+
this.emit('update',{message: `Step: ${this.stepNum}/${this.totalSteps}: playing the convolved calibration tone...`})
|
|
360
375
|
}
|
|
361
376
|
|
|
362
377
|
/** .
|
|
@@ -375,7 +390,8 @@ class ImpulseResponse extends AudioCalibrator {
|
|
|
375
390
|
this.offsetGainNode.gain.setTargetAtTime(0, this.sourceAudioContext.currentTime, 0.5);
|
|
376
391
|
this.calibrationNodes[0].stop(0);
|
|
377
392
|
this.sourceAudioContext.close();
|
|
378
|
-
this.
|
|
393
|
+
this.stepNum += 1;
|
|
394
|
+
this.emit('update', {message: `Step ${this.stepNum}/${this.totalSteps}: stopping the calibration tone...`});
|
|
379
395
|
};
|
|
380
396
|
|
|
381
397
|
#stopCalibrationAudioConvolved = () => {
|
|
@@ -388,7 +404,8 @@ class ImpulseResponse extends AudioCalibrator {
|
|
|
388
404
|
//this.calibrationNodesConvolved[0].stop(0);
|
|
389
405
|
console.log("right before closing volved audio context");
|
|
390
406
|
this.sourceAudioContextConvolved.close();
|
|
391
|
-
this.
|
|
407
|
+
this.stepNum += 1;
|
|
408
|
+
this.emit('update', {message: `Step ${this.stepNum}/${this.totalSteps}: stopping the convolved calibration tone...`});
|
|
392
409
|
|
|
393
410
|
}
|
|
394
411
|
|