BGC Tools
Public Types | Static Public Member Functions | Data Fields
BGC.Audio.Normalization Class Reference

A collection of some common procedures related to level scaling of Audio More...

Collaboration diagram for BGC.Audio.Normalization:
Collaboration graph
[legend]

Public Types

enum  Scheme { Scheme.RMS = 0, Scheme.Peak, Scheme.RMSProscribed, Scheme.MAX }
 

Static Public Member Functions

static void SPLToAdjustmentDB (double dbSPLL, double dbSPLR, out double dbAdjustL, out double dbAdjustR, Calibration.Source source=Calibration.Source.Custom)
 
static void GetAmplitudeFactors (double dbSPLL, double dbSPLR, out double factorL, out double factorR, Calibration.Source source=Calibration.Source.Custom)
 
static void Normalize (double desiredLevel, float[] samples, float[] destination=null, Scheme scheme=Scheme.RMS, Calibration.Source source=Calibration.Source.Custom)
 Normalize the input sound buffer. Leave destination null to normalize inplace. More...
 
static void Normalize (double desiredLevel, double effectiveRMS, float[] samples, float[] destination=null, Scheme scheme=Scheme.RMSProscribed, Calibration.Source source=Calibration.Source.Custom)
 Normalize the input sound buffer. Leave destination null to normalize inplace. More...
 
static float [] NormalizeMono (double desiredLevel, float[] monoInput, float[] stereoOutput=null, int inputOffset=0, int outputOffset=0, int sampleCount=int.MaxValue, Scheme scheme=Scheme.RMS, Calibration.Source source=Calibration.Source.Custom)
 Normalize the input sound buffer. Leave destination null to allocate a new stereo output array. More...
 
static float [] NormalizeMono (double desiredLevel, double effectiveRMS, float[] monoInput, float[] stereoOutput=null, int inputOffset=0, int outputOffset=0, int sampleCount=int.MaxValue, Scheme scheme=Scheme.RMS, Calibration.Source source=Calibration.Source.Custom)
 Normalize the input sound buffer. Leave destination null to allocate a new stereo output array. More...
 
static void NormalizeStereo_RMS (double levelFactorL, double levelFactorR, float[] samples, float[] destination=null)
 
static void NormalizeStereo_TargetRMS (double levelFactorL, double levelFactorR, double effectiveRMS, float[] samples, float[] destination=null)
 
static void NormalizeStereo_Peak (double levelFactorL, double levelFactorR, float[] samples, float[] destination=null)
 Peak Equivalence Level-Scaling More...
 
static float [] NormalizeMono_RMS (double levelFactorL, double levelFactorR, float[] monoInput, float[] stereoOutput=null, int inputOffset=0, int outputOffset=0, int sampleCount=int.MaxValue)
 
static float [] NormalizeMono_TargetRMS (double levelFactorL, double levelFactorR, double effectiveRMS, float[] monoInput, float[] stereoOutput=null, int inputOffset=0, int outputOffset=0, int sampleCount=int.MaxValue)
 
static float [] NormalizeMono_Peak (double levelFactorL, double levelFactorR, float[] monoInput, float[] stereoOutput=null, int inputOffset=0, int outputOffset=0, int sampleCount=int.MaxValue)
 Peak Equivalence Level-Scaling More...
 
static void GetRMSScalingFactors (IBGCStream stream, double desiredLevel, out double scalingFactorL, out double scalingFactorR, Calibration.Source source=Calibration.Source.Custom)
 
static void GetRMSScalingFactors (float[] stereoSamples, double desiredLevel, out float scalingFactorL, out float scalingFactorR, Calibration.Source source=Calibration.Source.Custom)
 
static void GetMonoRMSScalingFactors (float[] monoSamples, double desiredLevel, out double scalingFactorL, out double scalingFactorR, Calibration.Source source=Calibration.Source.Custom)
 
static double CalculateRMSLevel (float[] samples)
 
static void StandardizeSoundRMSMono (float[] samples)
 
static void StandardizeSoundRMSStereo (float[] samples)
 

Data Fields

const double dbMax = 90.0
 
const double dbOffset = 80.0
 
const double RMS_TO_PEAK = 2.8
 
const double TARGET_RMS = 1.0 / 128.0
 
const double TARGET_PEAK = TARGET_RMS * RMS_TO_PEAK
 

Detailed Description

A collection of some common procedures related to level scaling of Audio

Definition at line 11 of file Normalization.cs.

Member Enumeration Documentation

◆ Scheme

Enumerator
RMS 
Peak 
RMSProscribed 
MAX 

Definition at line 13 of file Normalization.cs.

14  {
15  RMS = 0,
16  Peak,
17  RMSProscribed,
18  MAX
19  }

Member Function Documentation

◆ CalculateRMSLevel()

static double BGC.Audio.Normalization.CalculateRMSLevel ( float []  samples)
inlinestatic

Definition at line 796 of file Normalization.cs.

References BGC.Audio.Calibration.GetLevelOffset().

797  {
798  double[] sampleSquaredSum = new double[2];
799  int sampleCount = samples.Length / 2;
800 
801  for (int i = 0; i < sampleCount; i++)
802  {
803  sampleSquaredSum[0] += samples[2 * i] * samples[2 * i];
804  sampleSquaredSum[1] += samples[2 * i + 1] * samples[2 * i + 1];
805  }
806 
807  sampleSquaredSum[0] = Math.Sqrt(sampleSquaredSum[0] / sampleCount);
808  sampleSquaredSum[1] = Math.Sqrt(sampleSquaredSum[1] / sampleCount);
809 
810  double rmsL = sampleSquaredSum[0];
811  double rmsR = sampleSquaredSum[1];
812 
813  double levelL = 20.0 * Math.Log10(rmsL / TARGET_RMS) + dbOffset;
814  double levelR = 20.0 * Math.Log10(rmsR / TARGET_RMS) + dbOffset;
815 
816  if (double.IsNaN(levelL) || double.IsInfinity(levelL))
817  {
818  levelL = -60.0;
819  }
820 
821  if (double.IsNaN(levelR) || double.IsInfinity(levelR))
822  {
823  levelR = -60.0;
824  }
825 
826  Calibration.GetLevelOffset(
827  level: levelL,
828  levelOffsetL: out double dbOffsetL,
829  levelOffsetR: out double dbOffsetR);
830 
831  if (levelL != levelR)
832  {
833  Calibration.GetLevelOffset(
834  level: levelR,
835  levelOffsetL: out _,
836  levelOffsetR: out dbOffsetR);
837  }
838 
839  return Math.Max(levelL - dbOffsetL, levelR - dbOffsetR);
840  }
Here is the call graph for this function:

◆ GetAmplitudeFactors()

static void BGC.Audio.Normalization.GetAmplitudeFactors ( double  dbSPLL,
double  dbSPLR,
out double  factorL,
out double  factorR,
Calibration.Source  source = Calibration.Source.Custom 
)
inlinestatic

Definition at line 60 of file Normalization.cs.

66  {
68  dbSPLL: dbSPLL,
69  dbSPLR: dbSPLR,
70  dbAdjustL: out double dbLevelL,
71  dbAdjustR: out double dbLevelR,
72  source: source);
73 
74  factorL = Math.Pow(10.0, dbLevelL / 20.0);
75  factorR = Math.Pow(10.0, dbLevelR / 20.0);
76  }
static void SPLToAdjustmentDB(double dbSPLL, double dbSPLR, out double dbAdjustL, out double dbAdjustR, Calibration.Source source=Calibration.Source.Custom)

◆ GetMonoRMSScalingFactors()

static void BGC.Audio.Normalization.GetMonoRMSScalingFactors ( float []  monoSamples,
double  desiredLevel,
out double  scalingFactorL,
out double  scalingFactorR,
Calibration.Source  source = Calibration.Source.Custom 
)
inlinestatic

Definition at line 758 of file Normalization.cs.

Referenced by BGC.Audio.NormalizedMonoClip._Initialize().

764  {
766  dbSPLL: desiredLevel,
767  dbSPLR: desiredLevel,
768  factorL: out double levelFactorL,
769  factorR: out double levelFactorR,
770  source: source);
771 
772  double sampleSquaredSum = 0.0;
773 
774  for (int i = 0; i < monoSamples.Length; i++)
775  {
776  sampleSquaredSum += monoSamples[i] * monoSamples[i];
777  }
778 
779  sampleSquaredSum = Math.Sqrt(sampleSquaredSum / monoSamples.Length);
780 
781  scalingFactorL = levelFactorL * (TARGET_RMS / sampleSquaredSum);
782  scalingFactorR = levelFactorR * (TARGET_RMS / sampleSquaredSum);
783 
784  //Protect against some NaN Poisoning
785  if (double.IsNaN(scalingFactorL) || double.IsInfinity(scalingFactorL))
786  {
787  scalingFactorL = 1.0;
788  }
789 
790  if (double.IsNaN(scalingFactorR) || double.IsInfinity(scalingFactorR))
791  {
792  scalingFactorR = 1.0;
793  }
794  }
static void GetAmplitudeFactors(double dbSPLL, double dbSPLR, out double factorL, out double factorR, Calibration.Source source=Calibration.Source.Custom)
Here is the caller graph for this function:

◆ GetRMSScalingFactors() [1/2]

static void BGC.Audio.Normalization.GetRMSScalingFactors ( IBGCStream  stream,
double  desiredLevel,
out double  scalingFactorL,
out double  scalingFactorR,
Calibration.Source  source = Calibration.Source.Custom 
)
inlinestatic

Definition at line 684 of file Normalization.cs.

References BGC.Audio.IBGCStream.GetChannelRMS().

Referenced by BGC.Audio.Filters.NormalizerMonoFilter._Initialize(), and BGC.Audio.Filters.NormalizerFilter._Initialize().

690  {
692  dbSPLL: desiredLevel,
693  dbSPLR: desiredLevel,
694  factorL: out double levelFactorL,
695  factorR: out double levelFactorR,
696  source: source);
697 
698  double maxRMS = stream.GetChannelRMS().Where(x => !double.IsNaN(x)).Max();
699 
700  scalingFactorL = levelFactorL * (TARGET_RMS / maxRMS);
701  scalingFactorR = levelFactorR * (TARGET_RMS / maxRMS);
702 
703  //Protect against some NaN Poisoning
704  if (double.IsNaN(scalingFactorL) || double.IsInfinity(scalingFactorL))
705  {
706  scalingFactorL = 1.0;
707  }
708 
709  if (double.IsNaN(scalingFactorR) || double.IsInfinity(scalingFactorR))
710  {
711  scalingFactorR = 1.0;
712  }
713  }
static void GetAmplitudeFactors(double dbSPLL, double dbSPLR, out double factorL, out double factorR, Calibration.Source source=Calibration.Source.Custom)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ GetRMSScalingFactors() [2/2]

static void BGC.Audio.Normalization.GetRMSScalingFactors ( float []  stereoSamples,
double  desiredLevel,
out float  scalingFactorL,
out float  scalingFactorR,
Calibration.Source  source = Calibration.Source.Custom 
)
inlinestatic

Definition at line 715 of file Normalization.cs.

721  {
723  dbSPLL: desiredLevel,
724  dbSPLR: desiredLevel,
725  factorL: out double levelFactorL,
726  factorR: out double levelFactorR,
727  source: source);
728 
729  double[] sampleSquaredSum = new double[2];
730  int sampleCount = stereoSamples.Length / 2;
731 
732  for (int i = 0; i < sampleCount; i++)
733  {
734  sampleSquaredSum[0] += stereoSamples[2 * i] * stereoSamples[2 * i];
735  sampleSquaredSum[1] += stereoSamples[2 * i + 1] * stereoSamples[2 * i + 1];
736  }
737 
738  sampleSquaredSum[0] = Math.Sqrt(sampleSquaredSum[0] / sampleCount);
739  sampleSquaredSum[1] = Math.Sqrt(sampleSquaredSum[1] / sampleCount);
740 
741  double maxRMS = Math.Max(sampleSquaredSum[0], sampleSquaredSum[1]);
742 
743  scalingFactorL = (float)(levelFactorL * (TARGET_RMS / maxRMS));
744  scalingFactorR = (float)(levelFactorR * (TARGET_RMS / maxRMS));
745 
746  //Protect against some NaN Poisoning
747  if (float.IsNaN(scalingFactorL) || float.IsInfinity(scalingFactorL))
748  {
749  scalingFactorL = 1f;
750  }
751 
752  if (float.IsNaN(scalingFactorR) || float.IsInfinity(scalingFactorR))
753  {
754  scalingFactorR = 1f;
755  }
756  }
static void GetAmplitudeFactors(double dbSPLL, double dbSPLR, out double factorL, out double factorR, Calibration.Source source=Calibration.Source.Custom)

◆ Normalize() [1/2]

static void BGC.Audio.Normalization.Normalize ( double  desiredLevel,
float []  samples,
float []  destination = null,
Scheme  scheme = Scheme.RMS,
Calibration.Source  source = Calibration.Source.Custom 
)
inlinestatic

Normalize the input sound buffer. Leave destination null to normalize inplace.

Parameters
samplesSource of samples, destination as well if samples is null
destinationLeave null to normalize in-place

Definition at line 83 of file Normalization.cs.

89  {
91  dbSPLL: desiredLevel,
92  dbSPLR: desiredLevel,
93  factorL: out double levelFactorL,
94  factorR: out double levelFactorR,
95  source: source);
96 
97  if (samples == destination)
98  {
99  //It is more efficient to leave destination null rather than passing in two
100  //references to the same array
101  destination = null;
102  }
103 
104  switch (scheme)
105  {
106  case Scheme.RMS:
108  levelFactorL: levelFactorL,
109  levelFactorR: levelFactorR,
110  samples: samples,
111  destination: destination);
112  break;
113 
114  case Scheme.Peak:
116  levelFactorL: levelFactorL,
117  levelFactorR: levelFactorR,
118  samples: samples,
119  destination: destination);
120  break;
121 
122  case Scheme.RMSProscribed:
123  Debug.LogError($"You must provide a effectiveRMS to use this Scheme.");
124  goto case Scheme.RMS;
125 
126  default:
127  Debug.LogError($"Unexpected Scheme: {scheme}");
128  goto case Scheme.RMS;
129  }
130  }
static void NormalizeStereo_RMS(double levelFactorL, double levelFactorR, float[] samples, float[] destination=null)
static void NormalizeStereo_Peak(double levelFactorL, double levelFactorR, float[] samples, float[] destination=null)
Peak Equivalence Level-Scaling
static void GetAmplitudeFactors(double dbSPLL, double dbSPLR, out double factorL, out double factorR, Calibration.Source source=Calibration.Source.Custom)

◆ Normalize() [2/2]

static void BGC.Audio.Normalization.Normalize ( double  desiredLevel,
double  effectiveRMS,
float []  samples,
float []  destination = null,
Scheme  scheme = Scheme.RMSProscribed,
Calibration.Source  source = Calibration.Source.Custom 
)
inlinestatic

Normalize the input sound buffer. Leave destination null to normalize inplace.

Parameters
samplesSource of samples, destination as well if samples is null
destinationLeave null to normalize in-place

Definition at line 137 of file Normalization.cs.

144  {
146  dbSPLL: desiredLevel,
147  dbSPLR: desiredLevel,
148  factorL: out double levelFactorL,
149  factorR: out double levelFactorR,
150  source: source);
151 
152  if (samples == destination)
153  {
154  //It is more efficient to leave destination null rather than passing in two
155  //references to the same array
156  destination = null;
157  }
158 
159  switch (scheme)
160  {
161  case Scheme.RMS:
162  Debug.LogError($"Argument effectiveRMS provided, but not meaningful.");
164  levelFactorL: levelFactorL,
165  levelFactorR: levelFactorR,
166  samples: samples,
167  destination: destination);
168  break;
169 
170  case Scheme.Peak:
171  Debug.LogError($"Argument effectiveRMS provided, but not meaningful.");
173  levelFactorL: levelFactorL,
174  levelFactorR: levelFactorR,
175  samples: samples,
176  destination: destination);
177  break;
178 
179  case Scheme.RMSProscribed:
181  levelFactorL: levelFactorL,
182  levelFactorR: levelFactorR,
183  effectiveRMS: effectiveRMS,
184  samples: samples,
185  destination: destination);
186  break;
187 
188  default:
189  Debug.LogError($"Unexpected Scheme: {scheme}");
190  goto case Scheme.RMSProscribed;
191  }
192  }
static void NormalizeStereo_RMS(double levelFactorL, double levelFactorR, float[] samples, float[] destination=null)
static void NormalizeStereo_TargetRMS(double levelFactorL, double levelFactorR, double effectiveRMS, float[] samples, float[] destination=null)
static void NormalizeStereo_Peak(double levelFactorL, double levelFactorR, float[] samples, float[] destination=null)
Peak Equivalence Level-Scaling
static void GetAmplitudeFactors(double dbSPLL, double dbSPLR, out double factorL, out double factorR, Calibration.Source source=Calibration.Source.Custom)

◆ NormalizeMono() [1/2]

static float [] BGC.Audio.Normalization.NormalizeMono ( double  desiredLevel,
float []  monoInput,
float []  stereoOutput = null,
int  inputOffset = 0,
int  outputOffset = 0,
int  sampleCount = int.MaxValue,
Scheme  scheme = Scheme.RMS,
Calibration.Source  source = Calibration.Source.Custom 
)
inlinestatic

Normalize the input sound buffer. Leave destination null to allocate a new stereo output array.

Definition at line 198 of file Normalization.cs.

207  {
209  dbSPLL: desiredLevel,
210  dbSPLR: desiredLevel,
211  factorL: out double levelFactorL,
212  factorR: out double levelFactorR,
213  source: source);
214 
215  switch (scheme)
216  {
217  case Scheme.RMS:
218  return NormalizeMono_RMS(
219  levelFactorL: levelFactorL,
220  levelFactorR: levelFactorR,
221  monoInput: monoInput,
222  stereoOutput: stereoOutput,
223  inputOffset: inputOffset,
224  outputOffset: outputOffset,
225  sampleCount: sampleCount);
226 
227  case Scheme.Peak:
228  return NormalizeMono_Peak(
229  levelFactorL: levelFactorL,
230  levelFactorR: levelFactorR,
231  monoInput: monoInput,
232  stereoOutput: stereoOutput,
233  inputOffset: inputOffset,
234  outputOffset: outputOffset,
235  sampleCount: sampleCount);
236 
237  case Scheme.RMSProscribed:
238  Debug.LogError($"You must provide a effectiveRMS to use this Scheme.");
239  goto case Scheme.RMS;
240 
241  default:
242  Debug.LogError($"Unexpected Scheme: {scheme}");
243  goto case Scheme.RMS;
244  }
245  }
static float [] NormalizeMono_Peak(double levelFactorL, double levelFactorR, float[] monoInput, float[] stereoOutput=null, int inputOffset=0, int outputOffset=0, int sampleCount=int.MaxValue)
Peak Equivalence Level-Scaling
static float [] NormalizeMono_RMS(double levelFactorL, double levelFactorR, float[] monoInput, float[] stereoOutput=null, int inputOffset=0, int outputOffset=0, int sampleCount=int.MaxValue)
static void GetAmplitudeFactors(double dbSPLL, double dbSPLR, out double factorL, out double factorR, Calibration.Source source=Calibration.Source.Custom)

◆ NormalizeMono() [2/2]

static float [] BGC.Audio.Normalization.NormalizeMono ( double  desiredLevel,
double  effectiveRMS,
float []  monoInput,
float []  stereoOutput = null,
int  inputOffset = 0,
int  outputOffset = 0,
int  sampleCount = int.MaxValue,
Scheme  scheme = Scheme.RMS,
Calibration.Source  source = Calibration.Source.Custom 
)
inlinestatic

Normalize the input sound buffer. Leave destination null to allocate a new stereo output array.

Definition at line 251 of file Normalization.cs.

261  {
263  dbSPLL: desiredLevel,
264  dbSPLR: desiredLevel,
265  factorL: out double levelFactorL,
266  factorR: out double levelFactorR,
267  source: source);
268 
269  switch (scheme)
270  {
271  case Scheme.RMS:
272  Debug.LogError($"Argument effectiveRMS provided, but not meaningful.");
273  return NormalizeMono_RMS(
274  levelFactorL: levelFactorL,
275  levelFactorR: levelFactorR,
276  monoInput: monoInput,
277  stereoOutput: stereoOutput,
278  inputOffset: inputOffset,
279  outputOffset: outputOffset,
280  sampleCount: sampleCount);
281 
282  case Scheme.Peak:
283  Debug.LogError($"Argument effectiveRMS provided, but not meaningful.");
284  return NormalizeMono_Peak(
285  levelFactorL: levelFactorL,
286  levelFactorR: levelFactorR,
287  monoInput: monoInput,
288  stereoOutput: stereoOutput,
289  inputOffset: inputOffset,
290  outputOffset: outputOffset,
291  sampleCount: sampleCount);
292 
293  case Scheme.RMSProscribed:
294  Debug.LogError($"You must provide a effectiveRMS to use this Scheme.");
296  levelFactorL: levelFactorL,
297  levelFactorR: levelFactorR,
298  effectiveRMS: effectiveRMS,
299  monoInput: monoInput,
300  stereoOutput: stereoOutput,
301  inputOffset: inputOffset,
302  outputOffset: outputOffset,
303  sampleCount: sampleCount);
304 
305  default:
306  Debug.LogError($"Unexpected Scheme: {scheme}");
307  goto case Scheme.RMS;
308  }
309  }
static float [] NormalizeMono_TargetRMS(double levelFactorL, double levelFactorR, double effectiveRMS, float[] monoInput, float[] stereoOutput=null, int inputOffset=0, int outputOffset=0, int sampleCount=int.MaxValue)
static float [] NormalizeMono_Peak(double levelFactorL, double levelFactorR, float[] monoInput, float[] stereoOutput=null, int inputOffset=0, int outputOffset=0, int sampleCount=int.MaxValue)
Peak Equivalence Level-Scaling
static float [] NormalizeMono_RMS(double levelFactorL, double levelFactorR, float[] monoInput, float[] stereoOutput=null, int inputOffset=0, int outputOffset=0, int sampleCount=int.MaxValue)
static void GetAmplitudeFactors(double dbSPLL, double dbSPLR, out double factorL, out double factorR, Calibration.Source source=Calibration.Source.Custom)

◆ NormalizeMono_Peak()

static float [] BGC.Audio.Normalization.NormalizeMono_Peak ( double  levelFactorL,
double  levelFactorR,
float []  monoInput,
float []  stereoOutput = null,
int  inputOffset = 0,
int  outputOffset = 0,
int  sampleCount = int.MaxValue 
)
inlinestatic

Peak Equivalence Level-Scaling

Definition at line 609 of file Normalization.cs.

617  {
618  if (sampleCount == int.MaxValue)
619  {
620  //Set sampleCount if the argument wasn't provided
621  if (stereoOutput == null)
622  {
623  //Determined by the input if we're creating the output
624  sampleCount = monoInput.Length - inputOffset;
625  }
626  else
627  {
628  //Determined by the smaller of the two if we are not
629  sampleCount = Math.Min(
630  monoInput.Length - inputOffset,
631  (stereoOutput.Length - 2 * outputOffset) / 2);
632 
633  }
634  }
635  else if (monoInput.Length < monoInput.Length - inputOffset)
636  {
637  //Except out if it was provided but was unusable
638  Debug.LogError($"Input length ({monoInput.Length}) shorter than required length ({monoInput.Length - inputOffset})");
639  return stereoOutput;
640  }
641 
642  if (stereoOutput == null)
643  {
644  //Create stereoOutput if the argument wasn't provided
645  stereoOutput = new float[2 * (sampleCount + outputOffset)];
646  }
647  else if (stereoOutput.Length < 2 * (sampleCount + outputOffset))
648  {
649  //Except out if it was provided but was unusable
650  Debug.LogError($"Output length ({stereoOutput.Length}) shorter than required length ({2 * (sampleCount + outputOffset)})");
651  return stereoOutput;
652  }
653 
654  double maxPeak = 0.0;
655  for (int i = 0; i < sampleCount; i++)
656  {
657  maxPeak = Math.Max(monoInput[i + inputOffset], maxPeak);
658  }
659 
660  float scalingFactorL = (float)(levelFactorL * (TARGET_PEAK / maxPeak));
661  float scalingFactorR = (float)(levelFactorR * (TARGET_PEAK / maxPeak));
662 
663  if (float.IsNaN(scalingFactorL) || float.IsInfinity(scalingFactorL))
664  {
665  scalingFactorL = 1f;
666  }
667 
668  if (float.IsNaN(scalingFactorR) || float.IsInfinity(scalingFactorR))
669  {
670  scalingFactorR = 1f;
671  }
672 
673  for (int i = 0; i < sampleCount; i++)
674  {
675  stereoOutput[2 * (i + outputOffset)] = monoInput[i + inputOffset] * scalingFactorL;
676  stereoOutput[2 * (i + outputOffset) + 1] = monoInput[i + inputOffset] * scalingFactorR;
677  }
678 
679  return stereoOutput;
680  }
const double TARGET_PEAK

◆ NormalizeMono_RMS()

static float [] BGC.Audio.Normalization.NormalizeMono_RMS ( double  levelFactorL,
double  levelFactorR,
float []  monoInput,
float []  stereoOutput = null,
int  inputOffset = 0,
int  outputOffset = 0,
int  sampleCount = int.MaxValue 
)
inlinestatic

Definition at line 471 of file Normalization.cs.

479  {
480  if (sampleCount == int.MaxValue)
481  {
482  //Set sampleCount if the argument wasn't provided
483  if (stereoOutput == null)
484  {
485  //Determined by the input if we're creating the output
486  sampleCount = monoInput.Length - inputOffset;
487  }
488  else
489  {
490  //Determined by the smaller of the two if we are not
491  sampleCount = Math.Min(
492  monoInput.Length - inputOffset,
493  (stereoOutput.Length - 2 * outputOffset) / 2);
494 
495  }
496  }
497  else if (monoInput.Length < monoInput.Length - inputOffset)
498  {
499  //Except out if it was provided but was unusable
500  Debug.LogError($"Input length ({monoInput.Length}) shorter than required length ({monoInput.Length - inputOffset})");
501  return stereoOutput;
502  }
503 
504  if (stereoOutput == null)
505  {
506  //Create stereoOutput if the argument wasn't provided
507  stereoOutput = new float[2 * (sampleCount + outputOffset)];
508  }
509  else if (stereoOutput.Length < 2 * (sampleCount + outputOffset))
510  {
511  //Except out if it was provided but was unusable
512  Debug.LogError($"Output length ({stereoOutput.Length}) shorter than required length ({2 * (sampleCount + outputOffset)})");
513  return stereoOutput;
514  }
515 
516  double sampleSquaredSum = 0.0;
517 
518  for (int i = 0; i < sampleCount; i++)
519  {
520  sampleSquaredSum += monoInput[i + inputOffset] * monoInput[i + inputOffset];
521  }
522 
523  double maxRMS = Math.Sqrt(sampleSquaredSum / sampleCount);
524 
525  float scalingFactorL = (float)(levelFactorL * (TARGET_RMS / maxRMS));
526  float scalingFactorR = (float)(levelFactorR * (TARGET_RMS / maxRMS));
527 
528  //Protect against some NaN Poisoning
529  if (float.IsNaN(scalingFactorL) || float.IsInfinity(scalingFactorL))
530  {
531  scalingFactorL = 1f;
532  }
533 
534  if (float.IsNaN(scalingFactorR) || float.IsInfinity(scalingFactorR))
535  {
536  scalingFactorR = 1f;
537  }
538 
539  for (int i = 0; i < sampleCount; i++)
540  {
541  stereoOutput[2 * (i + outputOffset)] = monoInput[i + inputOffset] * scalingFactorL;
542  stereoOutput[2 * (i + outputOffset) + 1] = monoInput[i + inputOffset] * scalingFactorR;
543  }
544 
545  return stereoOutput;
546  }

◆ NormalizeMono_TargetRMS()

static float [] BGC.Audio.Normalization.NormalizeMono_TargetRMS ( double  levelFactorL,
double  levelFactorR,
double  effectiveRMS,
float []  monoInput,
float []  stereoOutput = null,
int  inputOffset = 0,
int  outputOffset = 0,
int  sampleCount = int.MaxValue 
)
inlinestatic

Definition at line 548 of file Normalization.cs.

557  {
558  if (sampleCount == int.MaxValue)
559  {
560  //Set sampleCount if the argument wasn't provided
561  if (stereoOutput == null)
562  {
563  //Determined by the input if we're creating the output
564  sampleCount = monoInput.Length - inputOffset;
565  }
566  else
567  {
568  //Determined by the smaller of the two if we are not
569  sampleCount = Math.Min(
570  monoInput.Length - inputOffset,
571  (stereoOutput.Length - 2 * outputOffset) / 2);
572 
573  }
574  }
575  else if (monoInput.Length < monoInput.Length - inputOffset)
576  {
577  //Except out if it was provided but was unusable
578  Debug.LogError($"Input length ({monoInput.Length}) shorter than required length ({monoInput.Length - inputOffset})");
579  return stereoOutput;
580  }
581 
582  if (stereoOutput == null)
583  {
584  //Create stereoOutput if the argument wasn't provided
585  stereoOutput = new float[2 * (sampleCount + outputOffset)];
586  }
587  else if (stereoOutput.Length < 2 * (sampleCount + outputOffset))
588  {
589  //Except out if it was provided but was unusable
590  Debug.LogError($"Output length ({stereoOutput.Length}) shorter than required length ({2 * (sampleCount + outputOffset)})");
591  return stereoOutput;
592  }
593 
594  float scalingFactorL = (float)(levelFactorL * (TARGET_RMS / effectiveRMS));
595  float scalingFactorR = (float)(levelFactorR * (TARGET_RMS / effectiveRMS));
596 
597  for (int i = 0; i < sampleCount; i++)
598  {
599  stereoOutput[2 * (i + outputOffset)] = monoInput[i + inputOffset] * scalingFactorL;
600  stereoOutput[2 * (i + outputOffset) + 1] = monoInput[i + inputOffset] * scalingFactorR;
601  }
602 
603  return stereoOutput;
604  }

◆ NormalizeStereo_Peak()

static void BGC.Audio.Normalization.NormalizeStereo_Peak ( double  levelFactorL,
double  levelFactorR,
float []  samples,
float []  destination = null 
)
inlinestatic

Peak Equivalence Level-Scaling

Definition at line 414 of file Normalization.cs.

419  {
420  bool inplace = (destination == null);
421 
422  if (!inplace && destination.Length < samples.Length)
423  {
424  Debug.LogError($"Destination length ({destination.Length}) shorter than Source length ({samples.Length})");
425  return;
426  }
427 
428  double maxPeak = 0.0;
429  int sampleCount = samples.Length / 2;
430 
431  for (int i = 0; i < sampleCount; i++)
432  {
433  maxPeak = Math.Max(samples[2 * i], maxPeak);
434  maxPeak = Math.Max(samples[2 * i + 1], maxPeak);
435  }
436 
437  float scalingFactorL = (float)(levelFactorL * (TARGET_PEAK / maxPeak));
438  float scalingFactorR = (float)(levelFactorR * (TARGET_PEAK / maxPeak));
439 
440  if (float.IsNaN(scalingFactorL) || float.IsInfinity(scalingFactorL))
441  {
442  scalingFactorL = 1f;
443  }
444 
445  if (float.IsNaN(scalingFactorR) || float.IsInfinity(scalingFactorR))
446  {
447  scalingFactorR = 1f;
448  }
449 
450  if (inplace)
451  {
452  for (int i = 0; i < sampleCount; i++)
453  {
454  samples[2 * i] *= scalingFactorL;
455  samples[2 * i + 1] *= scalingFactorR;
456  }
457  }
458  else
459  {
460  for (int i = 0; i < sampleCount; i++)
461  {
462  destination[2 * i] = samples[2 * i] * scalingFactorL;
463  destination[2 * i + 1] = samples[2 * i + 1] * scalingFactorR;
464  }
465  }
466  }
const double TARGET_PEAK

◆ NormalizeStereo_RMS()

static void BGC.Audio.Normalization.NormalizeStereo_RMS ( double  levelFactorL,
double  levelFactorR,
float []  samples,
float []  destination = null 
)
inlinestatic

Definition at line 313 of file Normalization.cs.

318  {
319  bool inplace = (destination == null);
320 
321  if (!inplace && destination.Length < samples.Length)
322  {
323  Debug.LogError($"Destination length ({destination.Length}) shorter than Source length ({samples.Length})");
324  return;
325  }
326 
327  double[] sampleSquaredSum = new double[2];
328  int sampleCount = samples.Length / 2;
329 
330  for (int i = 0; i < sampleCount; i++)
331  {
332  sampleSquaredSum[0] += samples[2 * i] * samples[2 * i];
333  sampleSquaredSum[1] += samples[2 * i + 1] * samples[2 * i + 1];
334  }
335 
336  sampleSquaredSum[0] = Math.Sqrt(sampleSquaredSum[0] / sampleCount);
337  sampleSquaredSum[1] = Math.Sqrt(sampleSquaredSum[1] / sampleCount);
338 
339  double maxRMS = Math.Max(sampleSquaredSum[0], sampleSquaredSum[1]);
340 
341  float scalingFactorL = (float)(levelFactorL * (TARGET_RMS / maxRMS));
342  float scalingFactorR = (float)(levelFactorR * (TARGET_RMS / maxRMS));
343 
344  //Protect against some NaN Poisoning
345  if (float.IsNaN(scalingFactorL) || float.IsInfinity(scalingFactorL))
346  {
347  scalingFactorL = 1f;
348  }
349 
350  if (float.IsNaN(scalingFactorR) || float.IsInfinity(scalingFactorR))
351  {
352  scalingFactorR = 1f;
353  }
354 
355  if (inplace)
356  {
357  for (int i = 0; i < sampleCount; i++)
358  {
359  samples[2 * i] *= scalingFactorL;
360  samples[2 * i + 1] *= scalingFactorR;
361  }
362  }
363  else
364  {
365  for (int i = 0; i < sampleCount; i++)
366  {
367  destination[2 * i] = samples[2 * i] * scalingFactorL;
368  destination[2 * i + 1] = samples[2 * i + 1] * scalingFactorR;
369  }
370  }
371  }

◆ NormalizeStereo_TargetRMS()

static void BGC.Audio.Normalization.NormalizeStereo_TargetRMS ( double  levelFactorL,
double  levelFactorR,
double  effectiveRMS,
float []  samples,
float []  destination = null 
)
inlinestatic

Definition at line 373 of file Normalization.cs.

379  {
380  bool inplace = (destination == null);
381 
382  if (!inplace && destination.Length < samples.Length)
383  {
384  Debug.LogError($"Destination length ({destination.Length}) shorter than Source length ({samples.Length})");
385  return;
386  }
387 
388  int sampleCount = samples.Length / 2;
389 
390  float scalingFactorL = (float)(levelFactorL * (TARGET_RMS / effectiveRMS));
391  float scalingFactorR = (float)(levelFactorR * (TARGET_RMS / effectiveRMS));
392 
393  if (inplace)
394  {
395  for (int i = 0; i < sampleCount; i++)
396  {
397  samples[2 * i] *= scalingFactorL;
398  samples[2 * i + 1] *= scalingFactorR;
399  }
400  }
401  else
402  {
403  for (int i = 0; i < sampleCount; i++)
404  {
405  destination[2 * i] = samples[2 * i] * scalingFactorL;
406  destination[2 * i + 1] = samples[2 * i + 1] * scalingFactorR;
407  }
408  }
409  }

◆ SPLToAdjustmentDB()

static void BGC.Audio.Normalization.SPLToAdjustmentDB ( double  dbSPLL,
double  dbSPLR,
out double  dbAdjustL,
out double  dbAdjustR,
Calibration.Source  source = Calibration.Source.Custom 
)
inlinestatic

Definition at line 28 of file Normalization.cs.

References BGC.Mathematics.GeneralMath.Clamp(), and BGC.Audio.Calibration.GetLevelOffset().

34  {
35  dbSPLL = GeneralMath.Clamp(dbSPLL, -60, dbMax);
36  dbSPLR = GeneralMath.Clamp(dbSPLR, -60, dbMax);
37 
38  //Start with Left calculation
39  Calibration.GetLevelOffset(
40  level: dbSPLL,
41  levelOffsetL: out double dbOffsetL,
42  levelOffsetR: out double dbOffsetR,
43  source: source);
44 
45  dbAdjustL = dbOffsetL + dbSPLL - dbOffset;
46 
47  //If they're not the same, then generate a new set of offsets
48  if (dbSPLL != dbSPLR)
49  {
50  //To right calculation if it's different
51  Calibration.GetLevelOffset(
52  level: dbSPLR,
53  levelOffsetL: out _,
54  levelOffsetR: out dbOffsetR,
55  source: source);
56  }
57  dbAdjustR = dbOffsetR + dbSPLR - dbOffset;
58  }
static decimal Clamp(decimal value, decimal min, decimal max)
Here is the call graph for this function:

◆ StandardizeSoundRMSMono()

static void BGC.Audio.Normalization.StandardizeSoundRMSMono ( float []  samples)
inlinestatic

Definition at line 842 of file Normalization.cs.

843  {
844  double squaredSum = 0.0;
845  int sampleCount = samples.Length;
846 
847  for (int i = 0; i < sampleCount; i++)
848  {
849  squaredSum += samples[i] * samples[i];
850  }
851 
852  squaredSum = Math.Sqrt(squaredSum / sampleCount);
853 
854  float scalingFactor = (float)(TARGET_RMS / squaredSum);
855 
856  //Protect against some NaN Poisoning
857  if (float.IsNaN(scalingFactor) || float.IsInfinity(scalingFactor))
858  {
859  scalingFactor = 1f;
860  }
861 
862  for (int i = 0; i < sampleCount; i++)
863  {
864  samples[i] *= scalingFactor;
865  }
866  }

◆ StandardizeSoundRMSStereo()

static void BGC.Audio.Normalization.StandardizeSoundRMSStereo ( float []  samples)
inlinestatic

Definition at line 868 of file Normalization.cs.

869  {
870  double squaredSumL = 0.0;
871  double squaredSumR = 0.0;
872  int sampleCount = samples.Length / 2;
873 
874  for (int i = 0; i < sampleCount; i += 2)
875  {
876  squaredSumL += samples[i] * samples[i];
877  squaredSumR += samples[i + 1] * samples[i + 1];
878  }
879 
880  squaredSumL = Math.Sqrt(squaredSumL / sampleCount);
881  squaredSumR = Math.Sqrt(squaredSumR / sampleCount);
882 
883  double squaredSum = Math.Max(squaredSumL, squaredSumR);
884 
885  float scalingFactor = (float)(TARGET_RMS / squaredSum);
886 
887  //Protect against some NaN Poisoning
888  if (float.IsNaN(scalingFactor) || float.IsInfinity(scalingFactor))
889  {
890  scalingFactor = 1f;
891  Debug.LogError("NaN Scaling Factor");
892  }
893 
894  for (int i = 0; i < 2 * sampleCount; i++)
895  {
896  samples[i] *= scalingFactor;
897  }
898  }

Field Documentation

◆ dbMax

const double BGC.Audio.Normalization.dbMax = 90.0

Definition at line 21 of file Normalization.cs.

◆ dbOffset

const double BGC.Audio.Normalization.dbOffset = 80.0

Definition at line 22 of file Normalization.cs.

◆ RMS_TO_PEAK

const double BGC.Audio.Normalization.RMS_TO_PEAK = 2.8

Definition at line 24 of file Normalization.cs.

◆ TARGET_PEAK

const double BGC.Audio.Normalization.TARGET_PEAK = TARGET_RMS * RMS_TO_PEAK

Definition at line 26 of file Normalization.cs.

◆ TARGET_RMS

const double BGC.Audio.Normalization.TARGET_RMS = 1.0 / 128.0

Definition at line 25 of file Normalization.cs.


The documentation for this class was generated from the following file: