public static void GetRMSScalingFactors( IBGCStream stream, double desiredLevel, out double scalingFactorL, out double scalingFactorR, Calibration.Source source = Calibration.Source.Custom) { GetAmplitudeFactors( dbSPLL: desiredLevel, dbSPLR: desiredLevel, factorL: out double levelFactorL, factorR: out double levelFactorR, source: source); double maxRMS = stream.GetChannelRMS().Where(x => !double.IsNaN(x)).Max(); scalingFactorL = levelFactorL * (TARGET_RMS / maxRMS); scalingFactorR = levelFactorR * (TARGET_RMS / maxRMS); //Protect against some NaN Poisoning if (double.IsNaN(scalingFactorL) || double.IsInfinity(scalingFactorL)) { scalingFactorL = 1.0; } if (double.IsNaN(scalingFactorR) || double.IsInfinity(scalingFactorR)) { scalingFactorR = 1.0; } }
public static void SPLToAdjustmentDB( double dbSPLL, double dbSPLR, out double dbAdjustL, out double dbAdjustR, Calibration.Source source = Calibration.Source.Custom) { dbSPLL = GeneralMath.Clamp(dbSPLL, -60, dbMax); dbSPLR = GeneralMath.Clamp(dbSPLR, -60, dbMax); //Start with Left calculation Calibration.GetLevelOffset( level: dbSPLL, levelOffsetL: out double dbOffsetL, levelOffsetR: out double dbOffsetR, source: source); dbAdjustL = dbOffsetL + dbSPLL - dbOffset; //If they're not the same, then generate a new set of offsets // (It doesn't matter if we mess up OffsetL, we already finished using it) if (dbSPLL != dbSPLR) { //To right calculation if it's different Calibration.GetLevelOffset( level: dbSPLR, levelOffsetL: out dbOffsetL, levelOffsetR: out dbOffsetR, source: source); } dbAdjustR = dbOffsetR + dbSPLR - dbOffset; }
/// <summary> /// Normalize the input sound buffer. /// Leave destination null to allocate a new stereo output array. /// </summary> public 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) { GetAmplitudeFactors( dbSPLL: desiredLevel, dbSPLR: desiredLevel, factorL: out double levelFactorL, factorR: out double levelFactorR, source: source); switch (scheme) { case Scheme.RMS: Debug.LogError($"Argument effectiveRMS provided, but not meaningful."); return(NormalizeMono_RMS( levelFactorL: levelFactorL, levelFactorR: levelFactorR, monoInput: monoInput, stereoOutput: stereoOutput, inputOffset: inputOffset, outputOffset: outputOffset, sampleCount: sampleCount)); case Scheme.Peak: Debug.LogError($"Argument effectiveRMS provided, but not meaningful."); return(NormalizeMono_Peak( levelFactorL: levelFactorL, levelFactorR: levelFactorR, monoInput: monoInput, stereoOutput: stereoOutput, inputOffset: inputOffset, outputOffset: outputOffset, sampleCount: sampleCount)); case Scheme.RMSProscribed: Debug.LogError($"You must provide a effectiveRMS to use this Scheme."); return(NormalizeMono_TargetRMS( levelFactorL: levelFactorL, levelFactorR: levelFactorR, effectiveRMS: effectiveRMS, monoInput: monoInput, stereoOutput: stereoOutput, inputOffset: inputOffset, outputOffset: outputOffset, sampleCount: sampleCount)); default: Debug.LogError($"Unexpected Scheme: {scheme}"); goto case Scheme.RMS; } }
/// <summary> /// Normalize the input sound buffer. Leave destination null to normalize inplace. /// </summary> /// <param name="samples">Source of samples, destination as well if samples is null</param> /// <param name="destination">Leave null to normalize in-place</param> public static void Normalize( double desiredLevel, double effectiveRMS, float[] samples, float[] destination = null, Scheme scheme = Scheme.RMSAssigned, Calibration.Source source = Calibration.Source.Custom, bool safetyLimit = true) { GetAmplitudeFactors( dbSPLL: desiredLevel, dbSPLR: desiredLevel, factorL: out double levelFactorL, factorR: out double levelFactorR, source: source, safetyLimit: safetyLimit); if (samples == destination) { //It is more efficient to leave destination null rather than passing in two //references to the same array destination = null; } switch (scheme) { case Scheme.RMS: Debug.LogError($"Argument effectiveRMS provided, but not meaningful."); NormalizeStereo_RMS( levelFactorL: levelFactorL, levelFactorR: levelFactorR, samples: samples, destination: destination); break; case Scheme.Peak: Debug.LogError($"Argument effectiveRMS provided, but not meaningful."); NormalizeStereo_Peak( levelFactorL: levelFactorL, levelFactorR: levelFactorR, samples: samples, destination: destination); break; case Scheme.RMSAssigned: NormalizeStereo_TargetRMS( levelFactorL: levelFactorL, levelFactorR: levelFactorR, effectiveRMS: effectiveRMS, samples: samples, destination: destination); break; default: Debug.LogError($"Unexpected Scheme: {scheme}"); goto case Scheme.RMSAssigned; } }
public NormalizerFilter(IBGCStream stream, double presentationLevel) : base(stream) { if (stream.Channels != 2) { throw new ArgumentException("NormalizerFilter inner stream but have two channels."); } this.presentationLevel = presentationLevel; factorsInitialized = false; source = Calibration.Source.Custom; }
public static void GetRMSScalingFactors( IBGCStream stream, double desiredLevel, out double scalingFactorL, out double scalingFactorR, Calibration.Source source = Calibration.Source.Custom, bool safetyLimit = true) { GetAmplitudeFactors( dbSPLL: desiredLevel, dbSPLR: desiredLevel, factorL: out double levelFactorL, factorR: out double levelFactorR, source: source, safetyLimit: safetyLimit); IEnumerable <double> channelRMS = stream.GetChannelRMS(); if (channelRMS.Any(double.IsNaN)) { if (stream.ChannelSamples == int.MaxValue) { throw new StreamCompositionException("Unable to calculate the RMS of an infinite, unknowable stream. Try truncating."); } else { channelRMS = stream.CalculateRMS(); if (channelRMS.All(double.IsNaN)) { throw new StreamCompositionException("Unable to calculate the RMS of stream."); } } } double maxRMS = channelRMS.Where(x => !double.IsNaN(x)).Max(); scalingFactorL = levelFactorL / maxRMS; scalingFactorR = levelFactorR / maxRMS; //Protect against some NaN Poisoning if (double.IsNaN(scalingFactorL) || double.IsInfinity(scalingFactorL)) { scalingFactorL = 1.0; } if (double.IsNaN(scalingFactorR) || double.IsInfinity(scalingFactorR)) { scalingFactorR = 1.0; } }
/// <summary> /// Normalize the input sound buffer. /// Leave destination null to allocate a new stereo output array. /// </summary> public 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, bool safetyLimit = true) { GetAmplitudeFactors( dbSPLL: desiredLevel, dbSPLR: desiredLevel, factorL: out double levelFactorL, factorR: out double levelFactorR, source: source, safetyLimit: safetyLimit); switch (scheme) { case Scheme.RMS: return(NormalizeMono_RMS( levelFactorL: levelFactorL, levelFactorR: levelFactorR, monoInput: monoInput, stereoOutput: stereoOutput, inputOffset: inputOffset, outputOffset: outputOffset, sampleCount: sampleCount)); case Scheme.Peak: return(NormalizeMono_Peak( levelFactorL: levelFactorL, levelFactorR: levelFactorR, monoInput: monoInput, stereoOutput: stereoOutput, inputOffset: inputOffset, outputOffset: outputOffset, sampleCount: sampleCount)); case Scheme.RMSAssigned: Debug.LogError($"You must provide a effectiveRMS to use this Scheme."); goto case Scheme.RMS; default: Debug.LogError($"Unexpected Scheme: {scheme}"); goto case Scheme.RMS; } }
/// <summary> /// Normalize the input sound buffer. Leave destination null to normalize inplace. /// </summary> /// <param name="samples">Source of samples, destination as well if samples is null</param> /// <param name="destination">Leave null to normalize in-place</param> public static void Normalize( double desiredLevel, float[] samples, float[] destination = null, Scheme scheme = Scheme.RMS, Calibration.Source source = Calibration.Source.Custom) { GetAmplitudeFactors( dbSPLL: desiredLevel, dbSPLR: desiredLevel, factorL: out double levelFactorL, factorR: out double levelFactorR, source: source); if (samples == destination) { //It is more efficient to leave destination null rather than passing in two //references to the same array destination = null; } switch (scheme) { case Scheme.RMS: NormalizeStereo_RMS( levelFactorL: levelFactorL, levelFactorR: levelFactorR, samples: samples, destination: destination); break; case Scheme.Peak: NormalizeStereo_Peak( levelFactorL: levelFactorL, levelFactorR: levelFactorR, samples: samples, destination: destination); break; case Scheme.RMSProscribed: Debug.LogError($"You must provide a effectiveRMS to use this Scheme."); goto case Scheme.RMS; default: Debug.LogError($"Unexpected Scheme: {scheme}"); goto case Scheme.RMS; } }
public NormalizerFilter(IBGCStream stream, double leftFactor, double rightFactor) : base(stream) { if (stream.Channels != 2) { throw new ArgumentException("NormalizerFilter inner stream but have two channels."); } this.leftFactor = (float)leftFactor; this.rightFactor = (float)rightFactor; presentationLevel = 0.0; factorsInitialized = true; //Doesn't matter, we won't use this. source = Calibration.Source.MAX; }
public static void GetAmplitudeFactors( double dbSPLL, double dbSPLR, out double factorL, out double factorR, Calibration.Source source = Calibration.Source.Custom) { SPLToAdjustmentDB( dbSPLL: dbSPLL, dbSPLR: dbSPLR, dbAdjustL: out double dbLevelL, dbAdjustR: out double dbLevelR, source: source); factorL = Math.Pow(10.0, dbLevelL / 20.0); factorR = Math.Pow(10.0, dbLevelR / 20.0); }
public static void GetRMSScalingFactors( float[] stereoSamples, double desiredLevel, out float scalingFactorL, out float scalingFactorR, Calibration.Source source = Calibration.Source.Custom, bool safetyLimit = true) { GetAmplitudeFactors( dbSPLL: desiredLevel, dbSPLR: desiredLevel, factorL: out double levelFactorL, factorR: out double levelFactorR, source: source, safetyLimit: safetyLimit); double[] sampleSquaredSum = new double[2]; int sampleCount = stereoSamples.Length / 2; for (int i = 0; i < sampleCount; i++) { sampleSquaredSum[0] += stereoSamples[2 * i] * stereoSamples[2 * i]; sampleSquaredSum[1] += stereoSamples[2 * i + 1] * stereoSamples[2 * i + 1]; } sampleSquaredSum[0] = Math.Sqrt(sampleSquaredSum[0] / sampleCount); sampleSquaredSum[1] = Math.Sqrt(sampleSquaredSum[1] / sampleCount); double maxRMS = Math.Max(sampleSquaredSum[0], sampleSquaredSum[1]); scalingFactorL = (float)(levelFactorL / maxRMS); scalingFactorR = (float)(levelFactorR / maxRMS); //Protect against some NaN Poisoning if (float.IsNaN(scalingFactorL) || float.IsInfinity(scalingFactorL)) { scalingFactorL = 1f; } if (float.IsNaN(scalingFactorR) || float.IsInfinity(scalingFactorR)) { scalingFactorR = 1f; } }
public static void GetAmplitudeFactors( double dbSPLL, double dbSPLR, out double factorL, out double factorR, Calibration.Source source = Calibration.Source.Custom, bool safetyLimit = true) { if (safetyLimit && (dbSPLL > dbSafetyLimit || dbSPLR > dbSafetyLimit)) { throw new StreamCompositionException( $"Tried to exceed safety limit of 90dB without disengaging safety. " + $"Requested Level: {Math.Max(dbSPLL, dbSPLR)} dB"); } (factorL, factorR) = Calibration.GetLevelFactors( levelL: dbSPLL, levelR: dbSPLR, source: source); }
public static void GetMonoRMSScalingFactors( float[] monoSamples, double desiredLevel, out double scalingFactorL, out double scalingFactorR, Calibration.Source source = Calibration.Source.Custom, bool safetyLimit = true) { GetAmplitudeFactors( dbSPLL: desiredLevel, dbSPLR: desiredLevel, factorL: out double levelFactorL, factorR: out double levelFactorR, source: source, safetyLimit: safetyLimit); double sampleSquaredSum = 0.0; for (int i = 0; i < monoSamples.Length; i++) { sampleSquaredSum += monoSamples[i] * monoSamples[i]; } sampleSquaredSum = Math.Sqrt(sampleSquaredSum / monoSamples.Length); scalingFactorL = levelFactorL / sampleSquaredSum; scalingFactorR = levelFactorR / sampleSquaredSum; //Protect against some NaN Poisoning if (double.IsNaN(scalingFactorL) || double.IsInfinity(scalingFactorL)) { scalingFactorL = 1.0; } if (double.IsNaN(scalingFactorR) || double.IsInfinity(scalingFactorR)) { scalingFactorR = 1.0; } }