speaker-calibration 2.1.16 → 2.1.18
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/Procfile +1 -0
- package/dist/example/speaker.html +7 -1
- package/dist/example/speakerUI.js +39 -2
- package/dist/main.js +26 -4
- package/package.json +2 -2
- package/src/main.js +2 -0
- package/src/server/PythonServerAPI.js +53 -0
- package/src/tasks/combination/combination.js +845 -0
- package/src/tasks/combination/mlsGen/mlsGen.cpp +99 -0
- package/src/tasks/combination/mlsGen/mlsGen.hpp +304 -0
- package/src/tasks/combination/mlsGen/mlsGenInterface.js +131 -0
- package/src/tasks/combination/mlsGen/mlsGenTest.cpp +181 -0
- package/src/tasks/impulse-response/impulseResponse.js +65 -31
- package/src/tasks/volume/volume.js +37 -2
|
@@ -74,6 +74,34 @@ class ImpulseResponse extends AudioCalibrator {
|
|
|
74
74
|
/** @private */
|
|
75
75
|
convolution;
|
|
76
76
|
|
|
77
|
+
/** @private */
|
|
78
|
+
status_denominator = 6;
|
|
79
|
+
|
|
80
|
+
/** @private */
|
|
81
|
+
status_numerator = 0;
|
|
82
|
+
|
|
83
|
+
/** @private */
|
|
84
|
+
percent_complete = 0;
|
|
85
|
+
|
|
86
|
+
/** @private */
|
|
87
|
+
status = ``;
|
|
88
|
+
|
|
89
|
+
/**generate string template that gets reevaluated as variable increases */
|
|
90
|
+
generateTemplate = () => {
|
|
91
|
+
if (this.percent_complete > 100){
|
|
92
|
+
this.percent_complete = 100;
|
|
93
|
+
}
|
|
94
|
+
const template = `<div style="display: flex; justify-content: center;"><div style="width: 200px; height: 20px; border: 2px solid #000; border-radius: 10px;"><div style="width: ${this.percent_complete}%; height: 100%; background-color: #00aaff; border-radius: 8px;"></div></div></div>`;
|
|
95
|
+
return template;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** increment numerator and percent for status bar */
|
|
99
|
+
incrementStatusBar = () => {
|
|
100
|
+
this.status_numerator += 1;
|
|
101
|
+
this.percent_complete = (this.status_numerator/this.status_denominator)*100;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
|
|
77
105
|
/** .
|
|
78
106
|
* .
|
|
79
107
|
* .
|
|
@@ -91,9 +119,10 @@ class ImpulseResponse extends AudioCalibrator {
|
|
|
91
119
|
const lowHz = this.#lowHz;
|
|
92
120
|
const highHz = this.#highHz;
|
|
93
121
|
this.stepNum += 1;
|
|
94
|
-
this.
|
|
122
|
+
this.status = `computing the IIR...`.toString() + this.generateTemplate().toString();
|
|
123
|
+
this.emit('update', {message: this.status});
|
|
95
124
|
return this.pyServerAPI
|
|
96
|
-
.
|
|
125
|
+
.getInverseImpulseResponseWithRetry({
|
|
97
126
|
payload: filteredComputedIRs.slice(0, this.numCaptures),
|
|
98
127
|
mls,
|
|
99
128
|
lowHz,
|
|
@@ -102,7 +131,9 @@ class ImpulseResponse extends AudioCalibrator {
|
|
|
102
131
|
.then(res => {
|
|
103
132
|
console.log(res);
|
|
104
133
|
this.stepNum += 1;
|
|
105
|
-
this.
|
|
134
|
+
this.incrementStatusBar();
|
|
135
|
+
this.status = `done computing the IIR...`.toString() + this.generateTemplate().toString();
|
|
136
|
+
this.emit('update', {message: this.status});
|
|
106
137
|
this.invertedImpulseResponse = res["iir"];
|
|
107
138
|
this.convolution = res["convolution"];
|
|
108
139
|
})
|
|
@@ -128,7 +159,8 @@ class ImpulseResponse extends AudioCalibrator {
|
|
|
128
159
|
signalCsv && signalCsv.length > 0 ? csvToArray(signalCsv) : allSignals[numSignals - 1];
|
|
129
160
|
console.log('sending rec');
|
|
130
161
|
this.stepNum += 1;
|
|
131
|
-
this.
|
|
162
|
+
this.status = `computing the IR of the last recording...`.toString() + this.generateTemplate().toString();
|
|
163
|
+
this.emit('update', {message: this.status});
|
|
132
164
|
this.impulseResponses.push(
|
|
133
165
|
this.pyServerAPI
|
|
134
166
|
.getImpulseResponse({
|
|
@@ -142,11 +174,11 @@ class ImpulseResponse extends AudioCalibrator {
|
|
|
142
174
|
this.numSuccessfulCaptured += 1;
|
|
143
175
|
console.log("num succ capt: " + this.numSuccessfulCaptured);
|
|
144
176
|
this.stepNum += 1;
|
|
145
|
-
this.
|
|
146
|
-
|
|
147
|
-
});
|
|
177
|
+
this.incrementStatusBar();
|
|
178
|
+
this.status = `${this.numSuccessfulCaptured}/${this.numCaptures} IRs computed...`.toString() + this.generateTemplate().toString();
|
|
179
|
+
this.emit('update', {message: this.status});
|
|
180
|
+
return res;
|
|
148
181
|
}
|
|
149
|
-
return res;
|
|
150
182
|
})
|
|
151
183
|
.catch(err => {
|
|
152
184
|
console.error(err);
|
|
@@ -164,9 +196,8 @@ class ImpulseResponse extends AudioCalibrator {
|
|
|
164
196
|
// seconds per MLS = P / SR
|
|
165
197
|
// await N * P / SR
|
|
166
198
|
this.stepNum += 1;
|
|
167
|
-
this.
|
|
168
|
-
|
|
169
|
-
});
|
|
199
|
+
this.status = `sampling the calibration signal...`.toString() + this.generateTemplate().toString();
|
|
200
|
+
this.emit('update', {message: this.status});
|
|
170
201
|
await sleep((this.#P / this.sourceSamplingRate) * this.numMLSPerCapture);
|
|
171
202
|
};
|
|
172
203
|
|
|
@@ -179,9 +210,8 @@ class ImpulseResponse extends AudioCalibrator {
|
|
|
179
210
|
*/
|
|
180
211
|
#awaitSignalOnset = async () => {
|
|
181
212
|
this.stepNum += 1;
|
|
182
|
-
this.
|
|
183
|
-
|
|
184
|
-
});
|
|
213
|
+
this.status = `waiting for the signal to stabilize...`.toString() + this.generateTemplate().toString();
|
|
214
|
+
this.emit('update', {message: this.status});
|
|
185
215
|
await sleep(this.TAPER_SECS);
|
|
186
216
|
};
|
|
187
217
|
|
|
@@ -197,12 +227,12 @@ class ImpulseResponse extends AudioCalibrator {
|
|
|
197
227
|
};
|
|
198
228
|
|
|
199
229
|
#afterMLSwIIRRecord = () => {
|
|
200
|
-
if (this.numSuccessfulCaptured <
|
|
230
|
+
if (this.numSuccessfulCaptured < 1) {
|
|
201
231
|
this.numSuccessfulCaptured += 1;
|
|
202
232
|
this.stepNum += 1;
|
|
203
|
-
this.
|
|
204
|
-
|
|
205
|
-
});
|
|
233
|
+
this.incrementStatusBar();
|
|
234
|
+
this.status = `${this.numSuccessfulCaptured} recording of convolved MLS captured`.toString() + this.generateTemplate().toString();
|
|
235
|
+
this.emit('update', {message: this.status});
|
|
206
236
|
}
|
|
207
237
|
};
|
|
208
238
|
|
|
@@ -309,8 +339,6 @@ class ImpulseResponse extends AudioCalibrator {
|
|
|
309
339
|
*/
|
|
310
340
|
#setCalibrationNodesFromBuffer = (dataBufferArray = [this.#mlsBufferView]) => {
|
|
311
341
|
if (dataBufferArray.length === 1) {
|
|
312
|
-
console.log('data buffer aray');
|
|
313
|
-
console.log(dataBufferArray);
|
|
314
342
|
this.#createCalibrationNodeFromBuffer(dataBufferArray[0]);
|
|
315
343
|
} else {
|
|
316
344
|
throw new Error('The length of the data buffer array must be 1');
|
|
@@ -361,14 +389,16 @@ class ImpulseResponse extends AudioCalibrator {
|
|
|
361
389
|
this.calibrationNodes[0].start(0);
|
|
362
390
|
this.#mls = this.calibrationNodes[0].buffer.getChannelData(0);
|
|
363
391
|
this.stepNum += 1;
|
|
364
|
-
this.
|
|
392
|
+
this.status = `playing the calibration tone...`.toString() + this.generateTemplate().toString();
|
|
393
|
+
this.emit('update', {message: this.status});
|
|
365
394
|
};
|
|
366
395
|
|
|
367
396
|
|
|
368
397
|
#playCalibrationAudioConvolved = () => {
|
|
369
398
|
this.calibrationNodesConvolved[0].start(0);
|
|
370
399
|
this.stepNum += 1;
|
|
371
|
-
this.
|
|
400
|
+
this.status = `playing the convolved calibration tone...`.toString() + this.generateTemplate().toString();
|
|
401
|
+
this.emit('update', {message: this.status});
|
|
372
402
|
}
|
|
373
403
|
|
|
374
404
|
/** .
|
|
@@ -388,7 +418,8 @@ class ImpulseResponse extends AudioCalibrator {
|
|
|
388
418
|
this.calibrationNodes[0].stop(0);
|
|
389
419
|
this.sourceAudioContext.close();
|
|
390
420
|
this.stepNum += 1;
|
|
391
|
-
this.
|
|
421
|
+
this.status = `stopping the calibration tone...`.toString() + this.generateTemplate().toString();
|
|
422
|
+
this.emit('update', {message: this.status});
|
|
392
423
|
};
|
|
393
424
|
|
|
394
425
|
#stopCalibrationAudioConvolved = () => {
|
|
@@ -398,16 +429,14 @@ class ImpulseResponse extends AudioCalibrator {
|
|
|
398
429
|
);
|
|
399
430
|
|
|
400
431
|
this.offsetGainNode.gain.setTargetAtTime(0, this.sourceAudioContextConvolved.currentTime, 0.5);
|
|
401
|
-
//this.calibrationNodesConvolved[0].stop(0);
|
|
402
|
-
console.log("right before closing volved audio context");
|
|
403
432
|
this.sourceAudioContextConvolved.close();
|
|
404
433
|
this.stepNum += 1;
|
|
405
|
-
this.
|
|
434
|
+
this.status = `stopping the convolved calibration tone...`.toString() + this.generateTemplate().toString();
|
|
435
|
+
this.emit('update', {message: this.status});
|
|
406
436
|
|
|
407
437
|
}
|
|
408
438
|
|
|
409
439
|
playMLSwithIIR = async (stream, iir) => {
|
|
410
|
-
console.log('play mls with iir');
|
|
411
440
|
this.invertedImpulseResponse = iir;
|
|
412
441
|
// initialize the MLSGenInterface object with it's factory method
|
|
413
442
|
|
|
@@ -420,8 +449,6 @@ class ImpulseResponse extends AudioCalibrator {
|
|
|
420
449
|
this.#mlsBufferView = this.#mlsGenInterface.getMLS();
|
|
421
450
|
});
|
|
422
451
|
|
|
423
|
-
console.log('after mls factory'); //works up to here.
|
|
424
|
-
console.log(this.#mls);
|
|
425
452
|
// after intializating, start the calibration steps with garbage collection
|
|
426
453
|
await this.#mlsGenInterface.withGarbageCollection([
|
|
427
454
|
() =>
|
|
@@ -430,7 +457,7 @@ class ImpulseResponse extends AudioCalibrator {
|
|
|
430
457
|
this.#playCalibrationAudioConvolved, // play audio func (required)
|
|
431
458
|
this.#putInPythonConv, // before play func
|
|
432
459
|
this.#awaitSignalOnset, // before record
|
|
433
|
-
() => this.numSuccessfulCaptured < this.numCaptures
|
|
460
|
+
() => this.numSuccessfulCaptured < 1, // < this.numCaptures
|
|
434
461
|
this.#awaitDesiredMLSLength, // during record
|
|
435
462
|
this.#afterMLSwIIRRecord, // after record
|
|
436
463
|
'filtered'
|
|
@@ -490,12 +517,18 @@ class ImpulseResponse extends AudioCalibrator {
|
|
|
490
517
|
let unconv_rec = recs[0];
|
|
491
518
|
let conv_rec = conv_recs[0];
|
|
492
519
|
|
|
520
|
+
this.status = `computing the PSD graphs...`.toString() + this.generateTemplate().toString();
|
|
521
|
+
this.emit('update', {message: this.status});
|
|
522
|
+
|
|
493
523
|
let results = await this.pyServerAPI
|
|
494
|
-
.
|
|
524
|
+
.getPSDWithRetry({
|
|
495
525
|
unconv_rec,
|
|
496
526
|
conv_rec,
|
|
497
527
|
})
|
|
498
528
|
.then(res => {
|
|
529
|
+
this.incrementStatusBar();
|
|
530
|
+
this.status = `done computing the PSD graphs`.toString() + this.generateTemplate().toString();
|
|
531
|
+
this.emit('update', {message: this.status});
|
|
499
532
|
return res;
|
|
500
533
|
})
|
|
501
534
|
.catch(err => {
|
|
@@ -509,6 +542,7 @@ class ImpulseResponse extends AudioCalibrator {
|
|
|
509
542
|
"x_conv": results["x_conv"],
|
|
510
543
|
"y_conv": results["y_conv"]
|
|
511
544
|
}
|
|
545
|
+
|
|
512
546
|
if (this.#download) {
|
|
513
547
|
this.downloadSingleUnfilteredRecording();
|
|
514
548
|
this.downloadSingleFilteredRecording();
|
|
@@ -32,6 +32,33 @@ class Volume extends AudioCalibrator {
|
|
|
32
32
|
/** @private */
|
|
33
33
|
TAPER_SECS = 0.010; // seconds
|
|
34
34
|
|
|
35
|
+
/** @private */
|
|
36
|
+
status_denominator = 2;
|
|
37
|
+
|
|
38
|
+
/** @private */
|
|
39
|
+
status_numerator = 0;
|
|
40
|
+
|
|
41
|
+
/** @private */
|
|
42
|
+
percent_complete = 0;
|
|
43
|
+
|
|
44
|
+
/** @private */
|
|
45
|
+
status = ``;
|
|
46
|
+
|
|
47
|
+
/**generate string template that gets reevaluated as variable increases */
|
|
48
|
+
generateTemplate = () => {
|
|
49
|
+
if (this.percent_complete > 100){
|
|
50
|
+
this.percent_complete = 100;
|
|
51
|
+
}
|
|
52
|
+
const template = `<div style="display: flex; justify-content: center;"><div style="width: 200px; height: 20px; border: 2px solid #000; border-radius: 10px;"><div style="width: ${this.percent_complete}%; height: 100%; background-color: #00aaff; border-radius: 8px;"></div></div></div>`;
|
|
53
|
+
return template;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** increment numerator and percent for status bar */
|
|
57
|
+
incrementStatusBar = () => {
|
|
58
|
+
this.status_numerator += 1;
|
|
59
|
+
this.percent_complete = (this.status_numerator/this.status_denominator)*100;
|
|
60
|
+
}
|
|
61
|
+
|
|
35
62
|
handleIncomingData = data => {
|
|
36
63
|
console.log('Received data: ', data);
|
|
37
64
|
if (data.type === 'soundGainDBSPL') {
|
|
@@ -152,6 +179,7 @@ class Volume extends AudioCalibrator {
|
|
|
152
179
|
})
|
|
153
180
|
.then(res => {
|
|
154
181
|
if (this.outDBSPL === null) {
|
|
182
|
+
this.incrementStatusBar();
|
|
155
183
|
this.outDBSPL = res['outDbSPL'];
|
|
156
184
|
this.outDBSPL1000 = res['outDbSPL1000'];
|
|
157
185
|
this.THD = res['thd'];
|
|
@@ -164,6 +192,7 @@ class Volume extends AudioCalibrator {
|
|
|
164
192
|
|
|
165
193
|
startCalibration = async (stream, gainValues, lCalib = 104.92978421490648) => {
|
|
166
194
|
const trialIterations = gainValues.length;
|
|
195
|
+
this.status_denominator += trialIterations;
|
|
167
196
|
const thdValues = [];
|
|
168
197
|
const inDBValues = [];
|
|
169
198
|
let inDB = 0;
|
|
@@ -173,7 +202,8 @@ class Volume extends AudioCalibrator {
|
|
|
173
202
|
// do one calibration that will be discarded
|
|
174
203
|
const soundLevelToDiscard = -60;
|
|
175
204
|
const gainToDiscard = Math.pow(10, soundLevelToDiscard / 20);
|
|
176
|
-
this.
|
|
205
|
+
this.status = `Sound Level: ${soundLevelToDiscard} dB`.toString() + this.generateTemplate().toString();
|
|
206
|
+
this.emit('update', {message: this.status});
|
|
177
207
|
do {
|
|
178
208
|
// eslint-disable-next-line no-await-in-loop
|
|
179
209
|
await this.volumeCalibrationSteps(
|
|
@@ -198,7 +228,8 @@ class Volume extends AudioCalibrator {
|
|
|
198
228
|
// precision to 1 decimal place
|
|
199
229
|
inDB = Math.round(inDB * 10) / 10;
|
|
200
230
|
inDBValues.push(inDB);
|
|
201
|
-
this.
|
|
231
|
+
this.status = `Sound Level: ${inDB} dB`.toString() + this.generateTemplate().toString();
|
|
232
|
+
this.emit('update', {message: this.status});
|
|
202
233
|
do {
|
|
203
234
|
// eslint-disable-next-line no-await-in-loop
|
|
204
235
|
await this.volumeCalibrationSteps(
|
|
@@ -220,6 +251,7 @@ class Volume extends AudioCalibrator {
|
|
|
220
251
|
}
|
|
221
252
|
|
|
222
253
|
// get the volume calibration parameters from the server
|
|
254
|
+
|
|
223
255
|
const parameters = await this.pyServerAPI
|
|
224
256
|
.getVolumeCalibrationParameters({
|
|
225
257
|
inDBValues: inDBValues,
|
|
@@ -227,6 +259,9 @@ class Volume extends AudioCalibrator {
|
|
|
227
259
|
lCalib: lCalib,
|
|
228
260
|
})
|
|
229
261
|
.then(res => {
|
|
262
|
+
this.incrementStatusBar();
|
|
263
|
+
this.status = `done with 1000 Hz calibration`.toString() + this.generateTemplate().toString();
|
|
264
|
+
this.emit('update', {message: this.status});
|
|
230
265
|
return res;
|
|
231
266
|
});
|
|
232
267
|
const result = {
|