Exemplo n.º 1
0
 /// <summary>
 /// Gets the gain at a given frequency.
 /// </summary>
 public double this[double frequency] {
     get {
         int bandCount = bands.Count;
         if (bandCount == 0)
         {
             return(0);
         }
         int nextBand = 0, prevBand = 0;
         while (nextBand != bandCount && bands[nextBand].Frequency < frequency)
         {
             prevBand = nextBand;
             ++nextBand;
         }
         if (nextBand != bandCount && nextBand != 0)
         {
             return(QMath.Lerp(bands[prevBand].Gain, bands[nextBand].Gain,
                               QMath.LerpInverse(bands[prevBand].Frequency, bands[nextBand].Frequency, frequency)));
         }
         return(bands[prevBand].Gain);
     }
 }
Exemplo n.º 2
0
        /// <summary>
        /// Generate the left/right ear filters.
        /// </summary>
        /// <param name="right">The object is to the right of the <see cref="Listener"/>'s forward vector</param>
        /// <param name="samples">Single-channel downmixed samples to process</param>
        public void Generate(bool right, float[] samples)
        {
            float dirMul = -90;

            if (right)
            {
                dirMul = 90;
            }
            Vector3 sourceForward = new Vector3(0, dirMul, 0).RotateInverse(source.listener.Rotation).PlaceInSphere(),
                    dir           = source.Position - source.listener.Position;
            float distance        = dir.Length(),
                  rawAngle        = (float)Math.Acos(Vector3.Dot(sourceForward, dir) / distance),
                  angle           = rawAngle * VectorExtensions.Rad2Deg;

            distance /= distanceFactor;

            // Find bounding angles with discrete impulses
            int smallerAngle = 0;

            while (smallerAngle < angles.Length && angles[smallerAngle] < angle)
            {
                ++smallerAngle;
            }
            if (smallerAngle != 0)
            {
                --smallerAngle;
            }
            int largerAngle = smallerAngle + 1;

            if (largerAngle == angles.Length)
            {
                largerAngle = angles.Length - 1;
            }
            float angleRatio = Math.Min(QMath.LerpInverse(angles[smallerAngle], angles[largerAngle], angle), 1);

            // Find bounding distances with discrete impulses
            int smallerDistance = 0;

            while (smallerDistance < distances.Length && distances[smallerDistance] < distance)
            {
                ++smallerDistance;
            }
            if (smallerDistance != 0)
            {
                --smallerDistance;
            }
            int largerDistance = smallerDistance + 1;

            if (largerDistance == distances.Length)
            {
                largerDistance = distances.Length - 1;
            }
            float distanceRatio =
                Math.Clamp(QMath.LerpInverse(distances[smallerDistance], distances[largerDistance], distance), 0, 1);

            // Find impulse candidates and their weight
            float[][] candidates = new float[4][] {
                impulses[smallerAngle][smallerDistance],
                impulses[smallerAngle][largerDistance],
                impulses[largerAngle][smallerDistance],
                impulses[largerAngle][largerDistance]
            };
            float[] gains = new float[4] {
                (float)Math.Sqrt((1 - angleRatio) * (1 - distanceRatio)),
                (float)Math.Sqrt((1 - angleRatio) * distanceRatio),
                (float)Math.Sqrt(angleRatio * (1 - distanceRatio)),
                (float)Math.Sqrt(angleRatio * distanceRatio)
            };

            // Apply the ear canal's response
            Array.Clear(filter.Impulse, 0, filterSize);
            for (int candidate = 0; candidate < candidates.Length; ++candidate)
            {
                WaveformUtils.Mix(candidates[candidate], filter.Impulse, gains[candidate]);
            }
            filter.Process(samples);

            // Apply gains
            float angleDiff = (float)(Math.Sin(rawAngle) * .097f);
            float ratioDiff = (distance + angleDiff) * (VirtualizerFilter.referenceDistance - angleDiff) /
                              ((distance - angleDiff) * (VirtualizerFilter.referenceDistance + angleDiff));

            ratioDiff *= ratioDiff;
            if (right)
            {
                if (ratioDiff < 1)
                {
                    RightGain = ratioDiff;
                }
                else
                {
                    LeftGain = 1 / ratioDiff;
                }
            }
            else
            {
                if (ratioDiff < 1)
                {
                    LeftGain = ratioDiff;
                }
                else
                {
                    RightGain = 1 / ratioDiff;
                }
            }
        }