audiosegment.py
def normalize_spl_by_average(self, db):
        """
        Normalize the values in the AudioSegment so that its `spl` property
        gives `db`.

        .. note:: This method is currently broken - it returns an AudioSegment whose
                  values are much smaller than reasonable, yet which yield an SPL value
                  that equals the given `db`. Such an AudioSegment will not be serializable
                  as a WAV file, which will also break any method that relies on SOX.
                  I may remove this method in the future, since the SPL of an AudioSegment is
                  pretty questionable to begin with.

        :param db: The decibels to normalize average to.
        :returns: A new AudioSegment object whose values are changed so that their
                  average is `db`.
        :raises: ValueError if there are no samples in this AudioSegment.
        """
        arr = self.to_numpy_array().copy()
        if len(arr) == 0:
            raise ValueError("Cannot normalize the SPL of an empty AudioSegment")

        def rms(x):
            return np.sqrt(np.mean(np.square(x)))

        # Figure out what RMS we would like
        desired_rms = P_REF_PCM * ((10 ** (db/20.0)) - 1E-9)

        # Use successive approximation to solve
        ## Keep trying different multiplication factors until we get close enough or run out of time
        max_ntries = 50
        res_rms = 0.0
        ntries = 0
        factor = 0.1
        left = 0.0
        right = desired_rms
        while (ntries < max_ntries) and not util.isclose(res_rms, desired_rms, abs_tol=0.1):
            res_rms = rms(arr * factor)
            if res_rms < desired_rms:
                left = factor
            else:
                right = factor
            factor = 0.5 * (left + right)
            ntries += 1

        dtype_dict = {1: np.int8, 2: np.int16, 4: np.int32}
        dtype = dtype_dict[self.sample_width]
        new_seg = from_numpy_array(np.array(arr * factor, dtype=dtype), self.frame_rate)
        return new_seg
def normalize_spl_by_average(self, db):
        """
        Normalize the values in the AudioSegment so that its `spl` property
        gives `db`.

        .. note:: This method is currently broken - it returns an AudioSegment whose
                  values are much smaller than reasonable, yet which yield an SPL value
                  that equals the given `db`. Such an AudioSegment will not be serializable
                  as a WAV file, which will also break any method that relies on SOX.
                  I may remove this method in the future, since the SPL of an AudioSegment is
                  pretty questionable to begin with.

        :param db: The decibels to normalize average to.
        :returns: A new AudioSegment object whose values are changed so that their
                  average is `db`.
        :raises: ValueError if there are no samples in this AudioSegment.
        """
        arr = self.to_numpy_array().copy()
        if len(arr) == 0:
            raise ValueError("Cannot normalize the SPL of an empty AudioSegment")

        def rms(x):
            return np.sqrt(np.mean(np.square(x)))

        # Figure out what RMS we would like
        desired_rms = P_REF_PCM * ((10 ** (db/20.0)) - 1E-9)

        # Use successive approximation to solve
        ## Keep trying different multiplication factors until we get close enough or run out of time
        max_ntries = 50
        res_rms = 0.0
        ntries = 0
        factor = 0.1
        left = 0.0
        right = desired_rms
        while (ntries < max_ntries) and not util.isclose(res_rms, desired_rms, abs_tol=0.1):
            res_rms = rms(arr * factor)
            if res_rms < desired_rms:
                left = factor
            else:
                right = factor
            factor = 0.5 * (left + right)
            ntries += 1

        dtype_dict = {1: np.int8, 2: np.int16, 4: np.int32}
        dtype = dtype_dict[self.sample_width]
        new_seg = from_numpy_array(np.array(arr * factor, dtype=dtype), self.frame_rate)
        return new_seg
Normalize the values in the AudioSegment so that its `spl` property
        gives `db`.

        .. note:: This method is currently broken - it returns an AudioSegment whose
                  values are much smaller than reasonable, yet which yield an SPL value
                  that equals the given `db`. Such an AudioSegment will not be serializable
                  as a WAV file, which will also break any method that relies on SOX.
                  I may remove this method in the future, since the SPL of an AudioSegment is
                  pretty questionable to begin with.

        :param db: The decibels to normalize average to.
        :returns: A new AudioSegment object whose values are changed so that their
                  average is `db`.
        :raises: ValueError if there are no samples in this AudioSegment.