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;
            }
        }
Exemple #4
0
        /// <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;
        }
Exemple #6
0
        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;
            }
        }
Exemple #7
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);
        }
Exemple #11
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;
            }
        }
Exemple #12
0
        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);
        }
Exemple #13
0
        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;
            }
        }