speaker-calibration 2.2.0 → 2.2.2
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/example/i18n.js +6399 -6146
- package/dist/example/listener.html +8 -4
- package/dist/example/listener.js +72 -44
- package/dist/example/styles.css +17 -0
- package/dist/main.js +4 -4
- package/package.json +1 -1
- package/src/peer-connection/listener.js +2 -2
- package/src/peer-connection/speaker.js +5 -1
- package/src/server/PythonServerAPI.js +52 -1
- package/src/tasks/combination/combination.js +84 -13
- package/.vscode/settings.json +0 -3
package/package.json
CHANGED
|
@@ -169,7 +169,7 @@ class Listener extends AudioPeer {
|
|
|
169
169
|
}
|
|
170
170
|
|
|
171
171
|
if (capabilities.sampleRate) {
|
|
172
|
-
constraints.sampleRate =
|
|
172
|
+
constraints.sampleRate = 48000;
|
|
173
173
|
}
|
|
174
174
|
|
|
175
175
|
if (capabilities.sampleSize) {
|
|
@@ -211,7 +211,7 @@ class Listener extends AudioPeer {
|
|
|
211
211
|
// ? {echoCancellation: {exact: false}}
|
|
212
212
|
// : {}),
|
|
213
213
|
...(availableConstraints.sampleRate && availableConstraints.sampleRate == true
|
|
214
|
-
? {sampleRate: {ideal:
|
|
214
|
+
? {sampleRate: {ideal: 48000}}
|
|
215
215
|
: {}),
|
|
216
216
|
...(availableConstraints.sampleSize && availableConstraints.sampleSize == true
|
|
217
217
|
? {sampleSize: {ideal: 24}}
|
|
@@ -91,7 +91,11 @@ class Speaker extends AudioPeer {
|
|
|
91
91
|
params.knownIR,
|
|
92
92
|
params.microphoneName,
|
|
93
93
|
params.calibrateSoundCheck,
|
|
94
|
-
params.isSmartPhone
|
|
94
|
+
params.isSmartPhone,
|
|
95
|
+
params.calibrateSoundBurstRepeats,
|
|
96
|
+
params.calibrateSoundBurstSec,
|
|
97
|
+
params.calibrateSoundBurstsWarmup,
|
|
98
|
+
params.calibrateSoundHz
|
|
95
99
|
);
|
|
96
100
|
speaker.#removeUIElems();
|
|
97
101
|
resolve(speaker.result);
|
|
@@ -24,7 +24,7 @@ class PythonServerAPI {
|
|
|
24
24
|
* @returns
|
|
25
25
|
* @example
|
|
26
26
|
*/
|
|
27
|
-
getImpulseResponse = async ({mls, payload, sampleRate, P}) => {
|
|
27
|
+
getImpulseResponse = async ({mls, payload, sampleRate, P, numPeriods}) => {
|
|
28
28
|
const task = 'impulse-response';
|
|
29
29
|
let res = null;
|
|
30
30
|
|
|
@@ -36,6 +36,7 @@ class PythonServerAPI {
|
|
|
36
36
|
'sample-rate': sampleRate,
|
|
37
37
|
mls,
|
|
38
38
|
P,
|
|
39
|
+
numPeriods,
|
|
39
40
|
});
|
|
40
41
|
|
|
41
42
|
await axios({
|
|
@@ -56,6 +57,56 @@ class PythonServerAPI {
|
|
|
56
57
|
return res.data[task];
|
|
57
58
|
};
|
|
58
59
|
|
|
60
|
+
getMLS = async(length) => {
|
|
61
|
+
const task = 'mls';
|
|
62
|
+
let res = null
|
|
63
|
+
|
|
64
|
+
const data = JSON.stringify({
|
|
65
|
+
task,
|
|
66
|
+
'length':length,
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
await axios({
|
|
70
|
+
method:'post',
|
|
71
|
+
baseURL: PythonServerAPI.PYTHON_SERVER_URL,
|
|
72
|
+
url: `/task/${task}`,
|
|
73
|
+
headers: {
|
|
74
|
+
'Content-Type':'application/json',
|
|
75
|
+
},
|
|
76
|
+
data,
|
|
77
|
+
})
|
|
78
|
+
.then(response => {
|
|
79
|
+
res = response;
|
|
80
|
+
})
|
|
81
|
+
.catch(error => {
|
|
82
|
+
throw error;
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
return res.data[task];
|
|
86
|
+
}
|
|
87
|
+
getMLSWithRetry = async (length) => {
|
|
88
|
+
let retryCount = 0;
|
|
89
|
+
let response = null;
|
|
90
|
+
|
|
91
|
+
while (retryCount < this.MAX_RETRY_COUNT) {
|
|
92
|
+
try {
|
|
93
|
+
response = await this.getMLS(length);
|
|
94
|
+
// If the request is successful, break out of the loop
|
|
95
|
+
break;
|
|
96
|
+
} catch (error) {
|
|
97
|
+
console.error(`Error occurred. Retrying... (${retryCount + 1}/${this.MAX_RETRY_COUNT})`);
|
|
98
|
+
retryCount++;
|
|
99
|
+
await new Promise(resolve => setTimeout(resolve, this.RETRY_DELAY_MS));
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (response) {
|
|
104
|
+
return response;
|
|
105
|
+
} else {
|
|
106
|
+
throw new Error(`Failed to get MLS after ${this.MAX_RETRY_COUNT} attempts.`);
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
|
|
59
110
|
getPSD = async ({unconv_rec, conv_rec, sampleRate}) => {
|
|
60
111
|
const task = 'psd';
|
|
61
112
|
let res = null;
|
|
@@ -142,6 +142,14 @@ class Combination extends AudioCalibrator {
|
|
|
142
142
|
|
|
143
143
|
deviceName = null;
|
|
144
144
|
|
|
145
|
+
desired_time_per_mls = 0;
|
|
146
|
+
|
|
147
|
+
num_mls_to_skip = 0;
|
|
148
|
+
|
|
149
|
+
desired_sampling_rate = 0;
|
|
150
|
+
|
|
151
|
+
#currentConvolution = [];
|
|
152
|
+
|
|
145
153
|
/**generate string template that gets reevaluated as variable increases */
|
|
146
154
|
generateTemplate = () => {
|
|
147
155
|
if (this.percent_complete > 100) {
|
|
@@ -298,6 +306,7 @@ class Combination extends AudioCalibrator {
|
|
|
298
306
|
payload,
|
|
299
307
|
mls,
|
|
300
308
|
P: this.#P,
|
|
309
|
+
numPeriods: this.numMLSPerCapture,
|
|
301
310
|
})
|
|
302
311
|
.then(res => {
|
|
303
312
|
if (this.numSuccessfulCaptured < this.numCaptures) {
|
|
@@ -337,7 +346,23 @@ class Combination extends AudioCalibrator {
|
|
|
337
346
|
this.emit('update', {
|
|
338
347
|
message: this.status,
|
|
339
348
|
});
|
|
340
|
-
|
|
349
|
+
let time_to_wait = (this.#mls.length / this.sourceSamplingRate) * this.numMLSPerCapture;
|
|
350
|
+
await sleep(time_to_wait);
|
|
351
|
+
};
|
|
352
|
+
|
|
353
|
+
#awaitDesiredMLSLengthConvolved = async () => {
|
|
354
|
+
// seconds per MLS = P / SR
|
|
355
|
+
// await N * P / SR
|
|
356
|
+
this.stepNum += 1;
|
|
357
|
+
console.log('await desired length ' + this.stepNum);
|
|
358
|
+
this.status =
|
|
359
|
+
`All Hz Calibration: sampling the calibration signal...`.toString() + this.generateTemplate();
|
|
360
|
+
this.emit('update', {
|
|
361
|
+
message: this.status,
|
|
362
|
+
});
|
|
363
|
+
let time_to_wait =
|
|
364
|
+
(this.#currentConvolution.length / this.sourceSamplingRate) * this.numMLSPerCapture;
|
|
365
|
+
await sleep(time_to_wait);
|
|
341
366
|
};
|
|
342
367
|
|
|
343
368
|
/** .
|
|
@@ -356,7 +381,25 @@ class Combination extends AudioCalibrator {
|
|
|
356
381
|
this.emit('update', {
|
|
357
382
|
message: this.status,
|
|
358
383
|
});
|
|
359
|
-
|
|
384
|
+
let number_of_bursts_to_skip = this.num_mls_to_skip;
|
|
385
|
+
let time_to_sleep = this.#mls.length / this.sourceSamplingRate;
|
|
386
|
+
//await sleep(this.TAPER_SECS);
|
|
387
|
+
await sleep(time_to_sleep);
|
|
388
|
+
};
|
|
389
|
+
|
|
390
|
+
#awaitSignalOnsetConvolved = async () => {
|
|
391
|
+
this.stepNum += 1;
|
|
392
|
+
console.log('await signal onset ' + this.stepNum);
|
|
393
|
+
this.status =
|
|
394
|
+
`All Hz Calibration: waiting for the signal to stabilize...`.toString() +
|
|
395
|
+
this.generateTemplate();
|
|
396
|
+
this.emit('update', {
|
|
397
|
+
message: this.status,
|
|
398
|
+
});
|
|
399
|
+
let number_of_bursts_to_skip = this.num_mls_to_skip;
|
|
400
|
+
let time_to_sleep = this.#currentConvolution.length / this.sourceSamplingRate;
|
|
401
|
+
//await sleep(this.TAPER_SECS);
|
|
402
|
+
await sleep(time_to_sleep);
|
|
360
403
|
};
|
|
361
404
|
|
|
362
405
|
/**
|
|
@@ -463,8 +506,6 @@ class Combination extends AudioCalibrator {
|
|
|
463
506
|
} catch (error) {
|
|
464
507
|
console.error(error);
|
|
465
508
|
}
|
|
466
|
-
console.log('mls second, same?');
|
|
467
|
-
console.log(data);
|
|
468
509
|
const onsetGainNode = audioContext.createGain();
|
|
469
510
|
this.offsetGainNode = audioContext.createGain();
|
|
470
511
|
const source = audioContext.createBufferSource();
|
|
@@ -488,8 +529,6 @@ class Combination extends AudioCalibrator {
|
|
|
488
529
|
*/
|
|
489
530
|
#setCalibrationNodesFromBuffer = (dataBufferArray = [this.#mlsBufferView]) => {
|
|
490
531
|
if (dataBufferArray.length === 1) {
|
|
491
|
-
console.log('data buffer aray');
|
|
492
|
-
console.log(dataBufferArray);
|
|
493
532
|
this.#createCalibrationNodeFromBuffer(dataBufferArray[0]);
|
|
494
533
|
} else {
|
|
495
534
|
throw new Error('The length of the data buffer array must be 1');
|
|
@@ -505,6 +544,7 @@ class Combination extends AudioCalibrator {
|
|
|
505
544
|
|
|
506
545
|
//depends on goal
|
|
507
546
|
if (this._calibrateSoundCheck != 'system') {
|
|
547
|
+
this.#currentConvolution = this.componentConvolution;
|
|
508
548
|
const buffer = audioCtx.createBuffer(
|
|
509
549
|
1, // number of channels
|
|
510
550
|
this.componentConvolution.length,
|
|
@@ -529,6 +569,7 @@ class Combination extends AudioCalibrator {
|
|
|
529
569
|
|
|
530
570
|
this.addCalibrationNodeConvolved(source);
|
|
531
571
|
} else {
|
|
572
|
+
this.#currentConvolution = this.systemConvolution;
|
|
532
573
|
const buffer = audioCtx.createBuffer(
|
|
533
574
|
1, // number of channels
|
|
534
575
|
this.systemConvolution.length,
|
|
@@ -563,6 +604,10 @@ class Combination extends AudioCalibrator {
|
|
|
563
604
|
*/
|
|
564
605
|
#playCalibrationAudio = () => {
|
|
565
606
|
this.calibrationNodes[0].start(0);
|
|
607
|
+
console.log('sink sampling rate');
|
|
608
|
+
console.log(this.sinkSamplingRate);
|
|
609
|
+
console.log('source sampling rate');
|
|
610
|
+
console.log(this.sourceSamplingRate);
|
|
566
611
|
this.#mls = this.calibrationNodes[0].buffer.getChannelData(0);
|
|
567
612
|
this.stepNum += 1;
|
|
568
613
|
console.log('play calibration audio ' + this.stepNum);
|
|
@@ -574,6 +619,10 @@ class Combination extends AudioCalibrator {
|
|
|
574
619
|
|
|
575
620
|
#playCalibrationAudioConvolved = () => {
|
|
576
621
|
this.calibrationNodesConvolved[0].start(0);
|
|
622
|
+
console.log('sink sampling rate');
|
|
623
|
+
console.log(this.sinkSamplingRate);
|
|
624
|
+
console.log('source sampling rate');
|
|
625
|
+
console.log(this.sourceSamplingRate);
|
|
577
626
|
this.stepNum += 1;
|
|
578
627
|
console.log('play convolved audio ' + this.stepNum);
|
|
579
628
|
this.status =
|
|
@@ -635,11 +684,9 @@ class Combination extends AudioCalibrator {
|
|
|
635
684
|
this.sourceSamplingRate
|
|
636
685
|
).then(mlsGenInterface => {
|
|
637
686
|
this.#mlsGenInterface = mlsGenInterface;
|
|
638
|
-
this.#mlsBufferView = this.#mlsGenInterface.getMLS();
|
|
687
|
+
//this.#mlsBufferView = this.#mlsGenInterface.getMLS();
|
|
639
688
|
});
|
|
640
689
|
|
|
641
|
-
console.log('after mls factory'); //works up to here.
|
|
642
|
-
console.log(this.#mls);
|
|
643
690
|
// after intializating, start the calibration steps with garbage collection
|
|
644
691
|
await this.#mlsGenInterface.withGarbageCollection([
|
|
645
692
|
() =>
|
|
@@ -647,9 +694,9 @@ class Combination extends AudioCalibrator {
|
|
|
647
694
|
stream,
|
|
648
695
|
this.#playCalibrationAudioConvolved, // play audio func (required)
|
|
649
696
|
this.#putInPythonConv, // before play func
|
|
650
|
-
this.#
|
|
697
|
+
this.#awaitSignalOnsetConvolved, // before record
|
|
651
698
|
() => this.numSuccessfulCaptured < 1,
|
|
652
|
-
this.#
|
|
699
|
+
this.#awaitDesiredMLSLengthConvolved, // during record
|
|
653
700
|
this.#afterMLSwIIRRecord, // after record
|
|
654
701
|
'filtered'
|
|
655
702
|
),
|
|
@@ -673,9 +720,24 @@ class Combination extends AudioCalibrator {
|
|
|
673
720
|
this.sourceSamplingRate
|
|
674
721
|
).then(mlsGenInterface => {
|
|
675
722
|
this.#mlsGenInterface = mlsGenInterface;
|
|
676
|
-
this.#mlsBufferView = this.#mlsGenInterface.getMLS();
|
|
723
|
+
//this.#mlsBufferView = this.#mlsGenInterface.getMLS();
|
|
677
724
|
});
|
|
678
725
|
|
|
726
|
+
let desired_time = this.desired_time_per_mls;
|
|
727
|
+
|
|
728
|
+
length = this.sourceSamplingRate * desired_time;
|
|
729
|
+
//get mls here
|
|
730
|
+
await this.pyServerAPI
|
|
731
|
+
.getMLSWithRetry(length)
|
|
732
|
+
.then(res => {
|
|
733
|
+
console.log(res);
|
|
734
|
+
this.#mlsBufferView = res['mls'];
|
|
735
|
+
})
|
|
736
|
+
.catch(err => {
|
|
737
|
+
// this.emit('InvertedImpulseResponse', {res: false});
|
|
738
|
+
console.error(err);
|
|
739
|
+
});
|
|
740
|
+
|
|
679
741
|
// after intializating, start the calibration steps with garbage collection
|
|
680
742
|
await this.#mlsGenInterface.withGarbageCollection([
|
|
681
743
|
() =>
|
|
@@ -1155,8 +1217,17 @@ class Combination extends AudioCalibrator {
|
|
|
1155
1217
|
componentIR = null,
|
|
1156
1218
|
microphoneName = 'MiniDSP-UMIK1-711-4754-vertical',
|
|
1157
1219
|
_calibrateSoundCheck = 'goal', //GOAL PASSed in by default
|
|
1158
|
-
isSmartPhone = false
|
|
1220
|
+
isSmartPhone = false,
|
|
1221
|
+
_calibrateSoundBurstRepeats = 4,
|
|
1222
|
+
_calibrateSoundBurstSec = 1,
|
|
1223
|
+
_calibrateSoundBurstsWarmup = 1,
|
|
1224
|
+
_calibrateSoundHz = 48000
|
|
1159
1225
|
) => {
|
|
1226
|
+
this.numMLSPerCapture = _calibrateSoundBurstRepeats;
|
|
1227
|
+
this.desired_time_per_mls = _calibrateSoundBurstSec;
|
|
1228
|
+
this.num_mls_to_skip = _calibrateSoundBurstsWarmup;
|
|
1229
|
+
this.desired_sampling_rate = _calibrateSoundHz;
|
|
1230
|
+
|
|
1160
1231
|
//feed calibration goal here
|
|
1161
1232
|
this._calibrateSoundCheck = _calibrateSoundCheck;
|
|
1162
1233
|
//check if a componentIR was given to the system, if it isn't check for the microphone. using dummy data here bc we need to
|
package/.vscode/settings.json
DELETED