speaker-calibration 2.0.0 → 2.1.0
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/.eslintignore +72 -0
- package/.eslintrc.json +40 -0
- package/.gitignore +78 -0
- package/.prettierignore +70 -0
- package/.prettierrc +15 -0
- package/LICENSE +20 -20
- package/README.md +133 -133
- package/__mocks__/fileMock.js +1 -0
- package/__mocks__/styleMock.js +1 -0
- package/babel.config.js +3 -0
- package/coverage/clover.xml +71 -0
- package/coverage/coverage-final.json +224 -0
- package/coverage/lcov-report/PythonServerInterface.js.html +265 -0
- package/coverage/lcov-report/base.css +354 -0
- package/coverage/lcov-report/block-navigation.js +82 -0
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +123 -0
- package/coverage/lcov-report/prettify.css +101 -0
- package/coverage/lcov-report/prettify.js +937 -0
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +189 -0
- package/coverage/lcov-report/src/index.html +121 -0
- package/coverage/lcov-report/src/server/PythonServerInterface.js.html +268 -0
- package/coverage/lcov-report/src/server/index.html +123 -0
- package/coverage/lcov-report/src/tasks/audioCalibrator.js.html +499 -0
- package/coverage/lcov-report/src/tasks/audioRecorder.js.html +412 -0
- package/coverage/lcov-report/src/tasks/index.html +143 -0
- package/coverage/lcov-report/src/tasks/volume/index.html +123 -0
- package/coverage/lcov-report/src/tasks/volume/volume.js.html +409 -0
- package/coverage/lcov-report/src/utils.js.html +172 -0
- package/coverage/lcov.info +91 -0
- package/dist/example/Queen-Bohemian_Rhapsody.wav +0 -0
- package/dist/example/Queen-Bohemian_Rhapsody_g_filtered.wav +0 -0
- package/dist/example/index.html +47 -0
- package/dist/example/listener.html +89 -0
- package/dist/example/server.js +49 -0
- package/dist/example/speaker.html +126 -0
- package/dist/example/speakerUI.js +217 -0
- package/dist/example/styles.css +40 -0
- package/dist/main.js +1 -1
- package/dist/mlsGen.js +6814 -6814
- package/dist/mlsGen.wasm +0 -0
- package/doc/AudioCalibrator.html +417 -0
- package/doc/AudioPeer.html +251 -0
- package/doc/AudioRecorder.html +195 -0
- package/doc/ImpulseResponse.html +215 -0
- package/doc/Listener.html +308 -0
- package/doc/MlsGenInterface.html +226 -0
- package/doc/MyEventEmitter.html +274 -0
- package/doc/PythonServerAPI.html +109 -0
- package/doc/Speaker-Calibration-UML-Diagram.png +0 -0
- package/doc/Speaker.html +276 -0
- package/doc/Takes%20a%20target%20element%20where%20html%20elements%20will%20be%20appended..html +128 -0
- package/doc/Takes%20the%20url%20of%20the%20current%20site%0Aand%20a%20target%20element%20where%20html%20elements%20will%20be%20appended..html +138 -0
- package/doc/Takes%20the%20url%20of%20the%20current%20site%20and%20a%20target%20element%20where%20html%20elements%20will%20be%20appended..html +137 -0
- package/doc/Volume.html +88 -0
- package/doc/audioCalibrator.js.html +179 -0
- package/doc/audioPeer.js.html +175 -0
- package/doc/audioRecorder.js.html +163 -0
- package/doc/creates%20a%20new%20AudioRecorder%20instance.%20%0ASets%20up%20the%20audio%20context%20and%20file%20reader..html +114 -0
- package/doc/fonts/OpenSans-Bold-webfont.eot +0 -0
- package/doc/fonts/OpenSans-Bold-webfont.svg +1830 -0
- package/doc/fonts/OpenSans-Bold-webfont.woff +0 -0
- package/doc/fonts/OpenSans-BoldItalic-webfont.eot +0 -0
- package/doc/fonts/OpenSans-BoldItalic-webfont.svg +1830 -0
- package/doc/fonts/OpenSans-BoldItalic-webfont.woff +0 -0
- package/doc/fonts/OpenSans-Italic-webfont.eot +0 -0
- package/doc/fonts/OpenSans-Italic-webfont.svg +1830 -0
- package/doc/fonts/OpenSans-Italic-webfont.woff +0 -0
- package/doc/fonts/OpenSans-Light-webfont.eot +0 -0
- package/doc/fonts/OpenSans-Light-webfont.svg +1831 -0
- package/doc/fonts/OpenSans-Light-webfont.woff +0 -0
- package/doc/fonts/OpenSans-LightItalic-webfont.eot +0 -0
- package/doc/fonts/OpenSans-LightItalic-webfont.svg +1835 -0
- package/doc/fonts/OpenSans-LightItalic-webfont.woff +0 -0
- package/doc/fonts/OpenSans-Regular-webfont.eot +0 -0
- package/doc/fonts/OpenSans-Regular-webfont.svg +1831 -0
- package/doc/fonts/OpenSans-Regular-webfont.woff +0 -0
- package/doc/global.html +308 -0
- package/doc/index.html +58 -0
- package/doc/listener.js.html +170 -0
- package/doc/mlsGen_mlsGenInterface.js.html +117 -0
- package/doc/myEventEmitter.js.html +124 -0
- package/doc/peer-connection_audioPeer.js.html +188 -0
- package/doc/peer-connection_listener.js.html +311 -0
- package/doc/peer-connection_speaker.js.html +381 -0
- package/doc/sc-activity-diagram.png +0 -0
- package/doc/scripts/linenumber.js +25 -0
- package/doc/scripts/prettify/Apache-License-2.0.txt +202 -0
- package/doc/scripts/prettify/lang-css.js +24 -0
- package/doc/scripts/prettify/prettify.js +640 -0
- package/doc/server_PythonServerAPI.js.html +160 -0
- package/doc/speaker.js.html +248 -0
- package/doc/styles/jsdoc-default.css +371 -0
- package/doc/styles/prettify-jsdoc.css +111 -0
- package/doc/styles/prettify-tomorrow.css +163 -0
- package/doc/tasks_audioCalibrator.js.html +207 -0
- package/doc/tasks_audioRecorder.js.html +190 -0
- package/doc/tasks_impulse-response_impulseResponse.js.html +442 -0
- package/doc/tasks_impulse-response_mlsGen_mlsGenInterface.js.html +175 -0
- package/doc/tasks_volume_volume.js.html +185 -0
- package/doc/utils.js.html +105 -0
- package/jest.config.js +173 -0
- package/netlify.toml +27 -0
- package/package.json +67 -66
- package/src/index.html +21 -0
- package/src/main.js +21 -0
- package/src/myEventEmitter.js +83 -0
- package/src/peer-connection/audioPeer.js +151 -0
- package/src/peer-connection/listener.js +251 -0
- package/src/peer-connection/peerErrors.js +25 -0
- package/src/peer-connection/speaker.js +346 -0
- package/src/server/PythonServerAPI.js +117 -0
- package/src/tasks/audioCalibrator.js +218 -0
- package/src/tasks/audioRecorder.js +148 -0
- package/src/tasks/impulse-response/impulseResponse.js +436 -0
- package/src/tasks/impulse-response/mlsGen/mlsGen.cpp +99 -0
- package/src/tasks/impulse-response/mlsGen/mlsGen.hpp +304 -0
- package/src/tasks/impulse-response/mlsGen/mlsGenInterface.js +131 -0
- package/src/tasks/impulse-response/mlsGen/mlsGenTest.cpp +181 -0
- package/src/tasks/volume/volume.cpp +3 -0
- package/src/tasks/volume/volume.hpp +23 -0
- package/src/tasks/volume/volume.js +157 -0
- package/src/utils.js +55 -0
- package/webpack.config.js +37 -0
- package/README +0 -3
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import AudioCalibrator from '../audioCalibrator';
|
|
2
|
+
|
|
3
|
+
import {sleep} from '../../utils';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
class Volume extends AudioCalibrator {
|
|
9
|
+
/**
|
|
10
|
+
*
|
|
11
|
+
* @param root0
|
|
12
|
+
* @param root0.download
|
|
13
|
+
* @param root0.numCalibrationRounds
|
|
14
|
+
* @param root0.numCalibrationNodes
|
|
15
|
+
* @example
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/** @private */
|
|
19
|
+
#CALIBRATION_TONE_FREQUENCY = 1000; // Hz
|
|
20
|
+
|
|
21
|
+
/** @private */
|
|
22
|
+
#CALIBRATION_TONE_TYPE = 'sine';
|
|
23
|
+
|
|
24
|
+
/** @private */
|
|
25
|
+
#CALIBRATION_TONE_DURATION = 5; // seconds
|
|
26
|
+
|
|
27
|
+
/** @private */
|
|
28
|
+
soundGainDBSPL = null;
|
|
29
|
+
|
|
30
|
+
handleIncomingData = data => {
|
|
31
|
+
console.log('Received data: ', data);
|
|
32
|
+
if (data.type === 'soundGainDBSPL') {
|
|
33
|
+
this.soundGainDBSPL = data.value;
|
|
34
|
+
} else {
|
|
35
|
+
throw new Error(`Unknown data type: ${data.type}`);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
#getTruncatedSignal = (left = 3.5, right = 4.5) => {
|
|
40
|
+
const start = Math.floor(left * this.sourceSamplingRate);
|
|
41
|
+
const end = Math.floor(right * this.sourceSamplingRate);
|
|
42
|
+
const result = Array.from(this.getLastRecordedSignal().slice(start, end));
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* function to check that capture was properly made
|
|
46
|
+
* @param {*} list
|
|
47
|
+
*/
|
|
48
|
+
const checkResult = list => {
|
|
49
|
+
const setItem = new Set(list);
|
|
50
|
+
if (setItem.size === 1 && setItem.has(0)) {
|
|
51
|
+
console.warn(
|
|
52
|
+
'The last capture failed, all recorded signal is zero',
|
|
53
|
+
this.getAllRecordedSignals()
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
if (setItem.size === 0) {
|
|
57
|
+
console.warn('The last capture failed, no recorded signal');
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
checkResult(result);
|
|
61
|
+
return result;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
*
|
|
66
|
+
*
|
|
67
|
+
Construct a calibration Node with the calibration parameters and given gain value
|
|
68
|
+
* @param {*} gainValue
|
|
69
|
+
* */
|
|
70
|
+
#createCalibrationToneWithGainValue = gainValue => {
|
|
71
|
+
const audioContext = this.makeNewSourceAudioContext();
|
|
72
|
+
const oscilator = audioContext.createOscillator();
|
|
73
|
+
const gainNode = audioContext.createGain();
|
|
74
|
+
|
|
75
|
+
oscilator.frequency.value = this.#CALIBRATION_TONE_FREQUENCY;
|
|
76
|
+
oscilator.type = this.#CALIBRATION_TONE_TYPE;
|
|
77
|
+
gainNode.gain.value = gainValue;
|
|
78
|
+
|
|
79
|
+
oscilator.connect(gainNode);
|
|
80
|
+
gainNode.connect(audioContext.destination);
|
|
81
|
+
|
|
82
|
+
this.addCalibrationNode(oscilator);
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Construct a Calibration Node with the calibration parameters.
|
|
87
|
+
*
|
|
88
|
+
* @private
|
|
89
|
+
* @example
|
|
90
|
+
*/
|
|
91
|
+
#createCalibrationNode = () => {
|
|
92
|
+
const audioContext = this.makeNewSourceAudioContext();
|
|
93
|
+
const oscilator = audioContext.createOscillator();
|
|
94
|
+
const gainNode = audioContext.createGain();
|
|
95
|
+
|
|
96
|
+
oscilator.frequency.value = this.#CALIBRATION_TONE_FREQUENCY;
|
|
97
|
+
oscilator.type = this.#CALIBRATION_TONE_TYPE;
|
|
98
|
+
gainNode.gain.value = 0.04;
|
|
99
|
+
|
|
100
|
+
oscilator.connect(gainNode);
|
|
101
|
+
gainNode.connect(audioContext.destination);
|
|
102
|
+
|
|
103
|
+
this.addCalibrationNode(oscilator);
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
#playCalibrationAudio = async () => {
|
|
107
|
+
const totalDuration = this.#CALIBRATION_TONE_DURATION * 1.2;
|
|
108
|
+
|
|
109
|
+
this.calibrationNodes[0].start(0);
|
|
110
|
+
this.calibrationNodes[0].stop(totalDuration);
|
|
111
|
+
console.log(`Playing a buffer of ${this.#CALIBRATION_TONE_DURATION} seconds of audio`);
|
|
112
|
+
console.log(`Waiting a total of ${totalDuration} seconds`);
|
|
113
|
+
await sleep(totalDuration);
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
#sendToServerForProcessing = () => {
|
|
117
|
+
console.log('Sending data to server');
|
|
118
|
+
this.pyServerAPI
|
|
119
|
+
.getVolumeCalibration({
|
|
120
|
+
sampleRate: this.sourceSamplingRate,
|
|
121
|
+
payload: this.#getTruncatedSignal(),
|
|
122
|
+
})
|
|
123
|
+
.then(res => {
|
|
124
|
+
if (this.soundGainDBSPL === null) {
|
|
125
|
+
this.soundGainDBSPL = res;
|
|
126
|
+
}
|
|
127
|
+
})
|
|
128
|
+
.catch(err => {
|
|
129
|
+
console.warn(err);
|
|
130
|
+
});
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
startCalibration = async (stream, gainValues) => {
|
|
134
|
+
const trialIterations = gainValues.length;
|
|
135
|
+
const soundGainDBSPLValues = [];
|
|
136
|
+
// run the calibration at different gain values provided by the user
|
|
137
|
+
for (let i = 0; i < trialIterations; i++) {
|
|
138
|
+
do {
|
|
139
|
+
// console.log('Processing gain value: ', gainValues[i]);
|
|
140
|
+
// eslint-disable-next-line no-await-in-loop
|
|
141
|
+
await this.volumeCalibrationSteps(
|
|
142
|
+
stream,
|
|
143
|
+
this.#playCalibrationAudio,
|
|
144
|
+
this.#createCalibrationToneWithGainValue,
|
|
145
|
+
this.#sendToServerForProcessing,
|
|
146
|
+
gainValues[i]
|
|
147
|
+
);
|
|
148
|
+
} while (this.soundGainDBSPL === null);
|
|
149
|
+
soundGainDBSPLValues.push(this.soundGainDBSPL);
|
|
150
|
+
this.soundGainDBSPL = null;
|
|
151
|
+
}
|
|
152
|
+
// return this.soundGainDBSPL;
|
|
153
|
+
return soundGainDBSPLValues;
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export default Volume;
|
package/src/utils.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/** .
|
|
2
|
+
* .
|
|
3
|
+
* .
|
|
4
|
+
* Utlity function to pause execution for a given time
|
|
5
|
+
*
|
|
6
|
+
* @param {number} seconds
|
|
7
|
+
* @returns {Promise}
|
|
8
|
+
* @example
|
|
9
|
+
*/
|
|
10
|
+
const sleep = seconds =>
|
|
11
|
+
new Promise(resolve => {
|
|
12
|
+
setTimeout(resolve, seconds * 1000);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
/** .
|
|
16
|
+
* .
|
|
17
|
+
* .
|
|
18
|
+
* Uiltity function to create and save a CSV file from a buffer
|
|
19
|
+
*
|
|
20
|
+
* @param {*} data
|
|
21
|
+
* @param {*} filename
|
|
22
|
+
* @example
|
|
23
|
+
*/
|
|
24
|
+
const saveToCSV = (data, filename = 'recordedMLSignal.csv') => {
|
|
25
|
+
// console.log(data)
|
|
26
|
+
let csvContent = 'data:text/csv;charset=utf-8,';
|
|
27
|
+
|
|
28
|
+
data.forEach((val, idx) => {
|
|
29
|
+
csvContent += `${idx},${val}\r\n`;
|
|
30
|
+
});
|
|
31
|
+
const encodedUri = encodeURI(csvContent);
|
|
32
|
+
const link = document.createElement('a');
|
|
33
|
+
link.setAttribute('href', encodedUri);
|
|
34
|
+
link.setAttribute('download', filename);
|
|
35
|
+
document.body.appendChild(link);
|
|
36
|
+
link.click();
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
/** .
|
|
40
|
+
* .
|
|
41
|
+
* .
|
|
42
|
+
* Utility function to create a buffer from a CSV file
|
|
43
|
+
*
|
|
44
|
+
* @param {*} csvString
|
|
45
|
+
* @param {*} delimiter
|
|
46
|
+
* @returns
|
|
47
|
+
* @example
|
|
48
|
+
*/
|
|
49
|
+
const csvToArray = (csvString, delimiter = ',') =>
|
|
50
|
+
csvString
|
|
51
|
+
.trim()
|
|
52
|
+
.split('\n')
|
|
53
|
+
.map(row => parseFloat(row.trim().split(delimiter)[1]));
|
|
54
|
+
|
|
55
|
+
export {sleep, saveToCSV, csvToArray};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const {BundleAnalyzerPlugin} = require('webpack-bundle-analyzer');
|
|
3
|
+
|
|
4
|
+
const config = {
|
|
5
|
+
entry: {
|
|
6
|
+
main: './src/main.js',
|
|
7
|
+
},
|
|
8
|
+
output: {
|
|
9
|
+
path: path.resolve(__dirname, 'dist'),
|
|
10
|
+
filename: '[name].js',
|
|
11
|
+
library: {
|
|
12
|
+
name: 'speakerCalibrator',
|
|
13
|
+
type: 'umd',
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
module: {
|
|
17
|
+
rules: [
|
|
18
|
+
{
|
|
19
|
+
test: /\.css$/,
|
|
20
|
+
use: ['style-loader', 'css-loader'],
|
|
21
|
+
},
|
|
22
|
+
],
|
|
23
|
+
},
|
|
24
|
+
plugins: [],
|
|
25
|
+
resolve: {
|
|
26
|
+
fallback: {
|
|
27
|
+
path: require.resolve('path-browserify'),
|
|
28
|
+
fs: false,
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
if (process.env.WEBPACK_ANALYZE === 'true') {
|
|
34
|
+
config.plugins.push(new BundleAnalyzerPlugin());
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
module.exports = config;
|
package/README
DELETED