speaker-calibration 2.2.261 → 2.2.262

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "speaker-calibration",
3
- "version": "2.2.261",
3
+ "version": "2.2.262",
4
4
  "description": "Speaker calibration library for auditory testing",
5
5
  "main": "dist/main.js",
6
6
  "directories": {
@@ -71,19 +71,34 @@ class AudioCalibrator extends AudioRecorder {
71
71
  };
72
72
 
73
73
  addTimeStamp = taskName => {
74
- const currentTime = new Date().getTime(); // Current time in ms
75
- const elapsedTime = (currentTime - this.startTime) / 1000; // Convert to seconds
76
- const stepDuration = elapsedTime - this.currentTime;
77
-
78
- this.currentTime = elapsedTime; // Update for next step
79
-
80
- // Format numbers to 1 decimal place without padding
81
- const elapsedStr = elapsedTime.toFixed(1);
82
- const stepStr = stepDuration.toFixed(1);
83
-
84
- // Push timestamp string (without padding)
85
- this.timeStamp.push(`${elapsedStr} s. ${stepStr} s. ${taskName}`);
74
+ const currentTime = new Date().getTime(); // ms
75
+ const elapsedTime = (currentTime - this.startTime) / 1000; // s
76
+ const stepDuration = elapsedTime - this.currentTime;
77
+ const startTimeSec = elapsedTime - stepDuration;
78
+
79
+ this.currentTime = elapsedTime; // for the next call
80
+
81
+ const startStr = startTimeSec.toFixed(1);
82
+ const stepStr = stepDuration.toFixed(1);
83
+
84
+ if (taskName === "Plot results") {
85
+ // first push your normal Plot‐results line
86
+ this.timeStamp.push(
87
+ `${startStr} s. ∆ ${stepStr} s. ${taskName}`
88
+ );
89
+ // *then* push the final “Done” line using the final elapsedTime
90
+ const endStr = elapsedTime.toFixed(1);
91
+ this.timeStamp.push(
92
+ `${endStr} s. Done`
93
+ );
94
+ }
95
+ else {
96
+ this.timeStamp.push(
97
+ `${startStr} s. ∆ ${stepStr} s. ${taskName}`
98
+ );
99
+ }
86
100
  };
101
+
87
102
 
88
103
  recordBackground = async (
89
104
  stream,
@@ -268,7 +283,9 @@ class AudioCalibrator extends AudioRecorder {
268
283
  microphoneImpulseResponse,
269
284
  afterRecord = () => {},
270
285
  lCalib,
271
- checkRec
286
+ checkSD,
287
+ maxSD,
288
+ maxRetry
272
289
  ) => {
273
290
  const totalSec = this.CALIBRATION_TONE_DURATION;
274
291
  // Convolve with loudspeaker and microphone impulse responses
@@ -306,7 +323,25 @@ class AudioCalibrator extends AudioRecorder {
306
323
  this.saveVolumeRecording(convolvedSignalWithMicrophone);
307
324
 
308
325
  // Process the simulated recording
309
- await afterRecord(lCalib);
326
+ await afterRecord(lCalib);
327
+ const sd = await checkSD();
328
+ let sdMessage;
329
+ if (sd <= maxSD) {
330
+ console.log(`SD =${sd}, less than calibrateSound1000HzMaxSD_dB=${maxSD}`);
331
+ this.numCalibratingRoundsCompleted += maxRetry;
332
+ sdMessage = `. SD = ${sd} dB`;
333
+ } else {
334
+ // if exist the maxSD do it one more time and only one more time
335
+ console.log(`SD =${sd}, greater than calibrateSound1000HzMaxSD_dB=${maxSD}`);
336
+ this.numCalibratingRoundsCompleted += 1;
337
+ sdMessage = `. SD = ${sd} > ${this.calibrateSound1000HzMaxSD_dB} dB.`;
338
+ }
339
+ this.addTimeStamp(
340
+ `${this.calibrateSound1000HzPreSec.toFixed(1)}` +
341
+ `+${this.calibrateSound1000HzSec.toFixed(1)}` +
342
+ `+${this.calibrateSound1000HzPostSec.toFixed(1)} s. ` +
343
+ `1000 Hz at ${this.inDB} dB${sdMessage}`
344
+ );
310
345
  };
311
346
 
312
347
  /**
@@ -383,7 +383,7 @@ class Combination extends AudioCalibrator {
383
383
  flags = `<br> autoGainControl: ${this.flags.autoGainControl}, echoCancellation: ${this.flags.echoCancellation}, noiseSuppression: ${this.flags.noiseSuppression}`;
384
384
  }
385
385
  if (this.SDofFilteredRange['mls']) {
386
- MLSsd = `<br> Recorded MLS power SD: ${this.SDofFilteredRange['mls']} dB`;
386
+ MLSsd = `<br> Record MLS power SD: ${this.SDofFilteredRange['mls']} dB`;
387
387
  }
388
388
  if (this.SDofFilteredRange['system']) {
389
389
  systemSD = `<br> Loudspeaker+Microphone correction SD: ${this.SDofFilteredRange['system']} dB`;
@@ -521,7 +521,7 @@ class Combination extends AudioCalibrator {
521
521
  * @example
522
522
  */
523
523
  sendComponentImpulseResponsesToServerForProcessing = async () => {
524
- this.addTimeStamp('Compute component IIR');
524
+ this.addTimeStamp('Compute speaker or mic IIR');
525
525
  const computedIRs = await Promise.all(this.impulseResponses);
526
526
  const filteredComputedIRs = computedIRs.filter(element => {
527
527
  return element != undefined;
@@ -699,7 +699,7 @@ class Combination extends AudioCalibrator {
699
699
  const background_rec = background_rec_whole.slice(startIndex);
700
700
  console.log('Sending background recording to server for processing');
701
701
  let backgroundSec = this._calibrateSoundBackgroundSecs + 0.5;
702
- this.addTimeStamp(`Recorded ${backgroundSec.toFixed(1)} s of background.`);
702
+ this.addTimeStamp(`Record ${backgroundSec.toFixed(1)} s of background.`);
703
703
  const fBackground = this.sourceSamplingRate / this._calibrateSoundBurstDownsample;
704
704
  const background_rec_downsampled = this.downsampleSignal(
705
705
  background_rec,
@@ -789,7 +789,7 @@ class Combination extends AudioCalibrator {
789
789
  );
790
790
 
791
791
  this.addTimeStamp(
792
- `Recorded ${total_dur.toFixed(1)} s ` +
792
+ `Record ${total_dur.toFixed(1)} s ` +
793
793
  `(${pre.toFixed(1)} + ${repeats}×${burst.toFixed(1)} + ${post.toFixed(
794
794
  1
795
795
  )} s) of MLS ver.` +
@@ -797,7 +797,7 @@ class Combination extends AudioCalibrator {
797
797
  );
798
798
  this.recordingChecks['unfiltered'].push(result);
799
799
  this.recordingChecks['warnings'].push(
800
- `All Hz. Re-recorded because SD ${result['sd']} >
800
+ `All Hz. Re-record because SD ${result['sd']} >
801
801
  ${this._calibrateSoundBurstMaxSD_dB} dB`
802
802
  );
803
803
  this.status = this.generateTemplate(
@@ -818,10 +818,10 @@ class Combination extends AudioCalibrator {
818
818
  this._calibrateSoundBurstMaxSD_dB
819
819
  );
820
820
  this.addTimeStamp(
821
- `Recorded ${total_dur.toFixed(1)} s ` +
822
- `(${pre.toFixed(1)} + ${repeats}×${burst.toFixed(1)} + ${post.toFixed(
821
+ `Record ${total_dur.toFixed(1)} s ` +
822
+ `=${pre.toFixed(1)}+${repeats}×${burst.toFixed(1)}+${post.toFixed(
823
823
  1
824
- )} s) of MLS ver.` +
824
+ )} s of MLS ver.` +
825
825
  ` ${this.icapture}. SD = ${result['sd']} <= ${this._calibrateSoundBurstMaxSD_dB}`
826
826
  );
827
827
  } else {
@@ -832,8 +832,8 @@ class Combination extends AudioCalibrator {
832
832
  this._calibrateSoundBurstMaxSD_dB
833
833
  );
834
834
  this.addTimeStamp(
835
- `Recorded ${total_dur.toFixed(1)} s ` +
836
- `(${pre.toFixed(1)} + ${repeats}×${burst.toFixed(1)} + ${post.toFixed(1)} s)` +
835
+ `Record ${total_dur.toFixed(1)} s ` +
836
+ `=${pre.toFixed(1)}+${repeats}×${burst.toFixed(1)}+${post.toFixed(1)} s` +
837
837
  `of MLS ver. ${this.icapture}. SD = ${result['sd']} > ${this._calibrateSoundBurstMaxSD_dB}`
838
838
  );
839
839
  }
@@ -1365,7 +1365,7 @@ class Combination extends AudioCalibrator {
1365
1365
  console.error(err);
1366
1366
  });
1367
1367
 
1368
- this.addTimeStamp('Compute spectrum of filtered recording (component)');
1368
+ this.addTimeStamp('Compute spectrum of filtered recording (speaker or mic)');
1369
1369
  if (this.isCalibrating) return null;
1370
1370
  let component_conv_rec_psd = await this.pyServerAPI
1371
1371
  .getSubtractedPSDWithRetry(
@@ -1409,7 +1409,7 @@ class Combination extends AudioCalibrator {
1409
1409
 
1410
1410
  conv_rec = system_conv_recs[system_conv_recs.length - 1];
1411
1411
  //psd of system
1412
- this.addTimeStamp('Compute spectrum of filtered recording (system) and unfiltered recording');
1412
+ this.addTimeStamp('Compute spectrum of filtered recording (speaker+mic) and unfiltered recording');
1413
1413
  if (this.isCalibrating) return null;
1414
1414
  let system_recs_psd = await this.pyServerAPI
1415
1415
  .getPSDWithRetry({
@@ -1449,7 +1449,7 @@ class Combination extends AudioCalibrator {
1449
1449
  //iir w/ and without bandpass psd. done
1450
1450
  unconv_rec = this.componentInvertedImpulseResponseNoBandpass;
1451
1451
  conv_rec = this.componentInvertedImpulseResponse;
1452
- this.addTimeStamp('Compute spectrum of component IIR and component IIR no band pass');
1452
+ this.addTimeStamp('Compute spectrum of speaker or mic IIR and speaker or mic IIR no band pass');
1453
1453
  if (this.isCalibrating) return null;
1454
1454
  let component_iir_psd = await this.pyServerAPI
1455
1455
  .getPSDWithRetry({
@@ -1512,7 +1512,7 @@ class Combination extends AudioCalibrator {
1512
1512
  console.error(err);
1513
1513
  });
1514
1514
 
1515
- this.addTimeStamp('Compute spectrum of filtered MLS (system)');
1515
+ this.addTimeStamp('Compute spectrum of filtered MLS (speaker+mic)');
1516
1516
  if (this.isCalibrating) return null;
1517
1517
  let system_filtered_mls_psd = await this.pyServerAPI
1518
1518
  .getMLSPSDWithRetry({
@@ -1550,7 +1550,7 @@ class Combination extends AudioCalibrator {
1550
1550
  console.error(err);
1551
1551
  });
1552
1552
 
1553
- this.addTimeStamp('Compute spectrum of filtered MLS (component)');
1553
+ this.addTimeStamp('Compute spectrum of filtered MLS (speaker or mic)');
1554
1554
  if (this.isCalibrating) return null;
1555
1555
  let component_filtered_mls_psd = await this.pyServerAPI
1556
1556
  .getMLSPSDWithRetry({
@@ -1816,7 +1816,7 @@ class Combination extends AudioCalibrator {
1816
1816
  console.error(err);
1817
1817
  });
1818
1818
 
1819
- this.addTimeStamp('Compute spectrum recording of speaker+ mic IIR-filtered MLS recording');
1819
+ this.addTimeStamp('Compute spectrum of speaker+mic IIR-filtered MLS recording');
1820
1820
  if (this.isCalibrating) return null;
1821
1821
 
1822
1822
  let conv_results = await this.pyServerAPI
@@ -1889,7 +1889,7 @@ class Combination extends AudioCalibrator {
1889
1889
  });
1890
1890
  unconv_rec = this.systemInvertedImpulseResponseNoBandpass;
1891
1891
  conv_rec = this.systemInvertedImpulseResponse;
1892
- this.addTimeStamp('Compute spectrum of speaker +mic IIR, with and without bandpass');
1892
+ this.addTimeStamp('Compute spectrum of speaker+mic IIR, with and without bandpass');
1893
1893
  if (this.isCalibrating) return null;
1894
1894
  let system_iir_psd = await this.pyServerAPI
1895
1895
  .getPSDWithRetry({
@@ -2044,7 +2044,7 @@ class Combination extends AudioCalibrator {
2044
2044
  impulseResponses: [],
2045
2045
  };
2046
2046
  } else {
2047
- this.addTimeStamp('Compute spectrum of filtered recording (system) and unfiltered recording');
2047
+ this.addTimeStamp('Compute spectrum of filtered recording (speaker+mic) and unfiltered recording');
2048
2048
  if (this.isCalibrating) return null;
2049
2049
  const fMLS = this.sourceSamplingRate / this._calibrateSoundBurstDownsample;
2050
2050
  let results = await this.pyServerAPI
@@ -2084,7 +2084,7 @@ class Combination extends AudioCalibrator {
2084
2084
  //iir w/ and without bandpass psd
2085
2085
  unconv_rec = this.componentInvertedImpulseResponseNoBandpass;
2086
2086
  conv_rec = this.componentInvertedImpulseResponse;
2087
- this.addTimeStamp('Compute spectrum of component IIR and component IIR no band pass');
2087
+ this.addTimeStamp('Compute spectrum of speaker or mic IIR and speaker or mic IIR no band pass');
2088
2088
  if (this.isCalibrating) return null;
2089
2089
  let component_iir_psd = await this.pyServerAPI
2090
2090
  .getPSDWithRetry({
@@ -2585,7 +2585,7 @@ class Combination extends AudioCalibrator {
2585
2585
 
2586
2586
  const fMLS = this.sourceSamplingRate / this._calibrateSoundBurstDownsample;
2587
2587
 
2588
- this.addTimeStamp('Compute spectrum of component IIR and component IIR no band pass');
2588
+ this.addTimeStamp('Compute spectrum of speaker or mic IIR and speaker or mic IIR no band pass');
2589
2589
  if (this.isCalibrating) return null;
2590
2590
  let component_iir_psd = await this.pyServerAPI
2591
2591
  .getPSDWithRetry({
@@ -2713,7 +2713,7 @@ class Combination extends AudioCalibrator {
2713
2713
  if (this.isCalibrating) return null;
2714
2714
  this.percent_complete = 100;
2715
2715
  this.status = this.generateTemplate(`All Hz Calibration: Finished`.toString()).toString();
2716
- this.addTimeStamp('Done');
2716
+ this.addTimeStamp('Plot results');
2717
2717
  this.emit('update', {message: this.status});
2718
2718
 
2719
2719
  console.log('irr_ir_and_plots for none: ', iir_ir_and_plots);
@@ -2849,7 +2849,7 @@ class Combination extends AudioCalibrator {
2849
2849
  #playCalibrationAudioVolume = async () => {
2850
2850
  if (this.numCalibratingRoundsCompleted == 1) {
2851
2851
  this.recordingChecks['warnings'].push(
2852
- `1000Hz. Re-recorded ${this.inDB} dB because SD ${
2852
+ `1000Hz. Re-record ${this.inDB} dB because SD ${
2853
2853
  this.recordingChecks['volume'][this.inDB]['sd']
2854
2854
  } > ${this.calibrateSound1000HzMaxSD_dB} dB`
2855
2855
  );
@@ -3001,7 +3001,11 @@ class Combination extends AudioCalibrator {
3001
3001
  this.calibrateSoundSimulateMicrophone1000Hz,
3002
3002
  this.#sendToServerForProcessing,
3003
3003
  lCalib,
3004
- checkRec
3004
+ () => {
3005
+ return this.recordingChecks['volume'][this.inDB]['sd'];
3006
+ },
3007
+ this.calibrateSound1000HzMaxSD_dB,
3008
+ this.calibrateSound1000HzMaxTries
3005
3009
  );
3006
3010
  } else {
3007
3011
  // Use actual recording mode
@@ -3063,7 +3067,11 @@ class Combination extends AudioCalibrator {
3063
3067
  this.calibrateSoundSimulateMicrophone1000Hz,
3064
3068
  this.#sendToServerForProcessing,
3065
3069
  lCalib,
3066
- checkRec
3070
+ () => {
3071
+ return this.recordingChecks['volume'][this.inDB]['sd'];
3072
+ },
3073
+ this.calibrateSound1000HzMaxSD_dB,
3074
+ this.calibrateSound1000HzMaxTries
3067
3075
  );
3068
3076
  } else {
3069
3077
  // Use actual recording mode
@@ -3371,12 +3379,27 @@ class Combination extends AudioCalibrator {
3371
3379
  this._calibrateSoundBurstPreSec +
3372
3380
  this._calibrateSoundBurstRepeats * this._calibrateSoundBurstSec +
3373
3381
  this._calibrateSoundBurstPostSec;
3382
+
3383
+ let soundCheckLabel;
3384
+ if (this.soundCheck === 'component')
3385
+ {
3386
+ soundCheckLabel = 'speaker or mic';
3387
+ }
3388
+ else if (this.soundCheck === 'speakerAndMic')
3389
+ {
3390
+ soundCheckLabel = 'speaker+mic';
3391
+ }
3392
+ else {
3393
+ soundCheckLabel = this.soundCheck;
3394
+ }
3395
+
3374
3396
  if (result['sd'] > this._calibrateSoundBurstMaxSD_dB && this.numSuccessfulCaptured == 0) {
3397
+
3375
3398
  this.addTimeStamp(
3376
- `Recorded ${total_dur} s of MLS with ${this.soundCheck} IIR. SD = ${result['sd']} > ${this._calibrateSoundBurstMaxSD_dB} dB`
3399
+ `Record ${total_dur} s of MLS with ${soundCheckLabel} IIR. SD = ${result['sd']} > ${this._calibrateSoundBurstMaxSD_dB} dB`
3377
3400
  );
3378
3401
  this.recordingChecks['warnings'].push(
3379
- `All Hz. Re-recorded ${this.inDB} because SD ${result['sd']} > ${this._calibrateSoundBurstMaxSD_dB} dB`
3402
+ `All Hz. Re-record ${this.inDB} because SD ${result['sd']} > ${this._calibrateSoundBurstMaxSD_dB} dB`
3380
3403
  );
3381
3404
  this.status = this.generateTemplate(
3382
3405
  `All Hz: Re-recording at ${this.inDB} dB because SD ${result['sd']} > ${this._calibrateSoundBurstMaxSD_dB} dB`.toString()
@@ -3390,10 +3413,12 @@ class Combination extends AudioCalibrator {
3390
3413
  this.numSuccessfulCaptured += 1;
3391
3414
  } else {
3392
3415
  this.addTimeStamp(
3393
- `Recorded ${total_dur} s of MLS with ${this.soundCheck} IIR. SD = ${result['sd']} ${
3416
+ `Record ${total_dur} s of MLS with ${soundCheckLabel} IIR. SD = ${result['sd']} ${
3394
3417
  result['sd'] > this._calibrateSoundBurstMaxSD_dB ? '>' : '<='
3395
3418
  } ${this._calibrateSoundBurstMaxSD_dB} dB`
3396
3419
  );
3420
+ console.log('this.recordingChecks: ', this.recordingChecks);
3421
+ console.log('this.soundCheck: ', this.soundCheck);
3397
3422
  this.recordingChecks[this.soundCheck].push(result);
3398
3423
  // Now we do at most 2 attempts if sd > _calibrateSoundBurstMaxSD_dB
3399
3424
  // Second attempt is the final