Пример #1
0
        /// <summary>
        /// 初期設定する
        /// </summary>
        /// <param name="room"></param>
        public void Start(WWRoom room)
        {
            var leftEarPos  = room.ListenerEarPos(0);
            var rightEarPos = room.ListenerEarPos(1);

            var leftSpeakerPos  = room.SpeakerPos(0);
            var rightSpeakerPos = room.SpeakerPos(1);

            // 左スピーカーから左の耳に音が届く
            var ll  = leftEarPos - leftSpeakerPos;
            var llN = ll;

            llN.Normalize();

            // エネルギーは、距離の2乗に反比例する
            // 振幅は、距離の1乗に反比例
            // ということにする。

            mLeftSpeakerToLeftEar.Add(new WWFirCoefficient(ll.Length / SoundSpeed, llN, 1.0 / ll.Length, true));

            // 右スピーカーから右の耳に音が届く
            var rr  = rightEarPos - rightSpeakerPos;
            var rrN = rr;

            rrN.Normalize();
            mRightSpeakerToRightEar.Add(new WWFirCoefficient(rr.Length / SoundSpeed, rrN, 1.0 / rr.Length, true));

            double gain = 1.0;

            if (WallReflectionType == ReflectionType.Specular)
            {
                // なんとなく、高音は逆の耳に届きにくい感じ。
                gain = 1.0 / 1.414;
            }

            // 左スピーカーから右の耳に音が届く。
            // 振幅が-3dBくらいになる。
            double attenuationDecibel   = -3.0;
            double attenuationMagnitude = Math.Pow(10.0, attenuationDecibel / 20.0);

            var lr  = rightEarPos - leftSpeakerPos;
            var lrN = lr;

            lrN.Normalize();
            mLeftSpeakerToRightEar.Add(new WWFirCoefficient(lr.Length / SoundSpeed, lrN, gain * attenuationMagnitude / lr.Length, true));

            var rl  = leftEarPos - rightSpeakerPos;
            var rlN = rl;

            rlN.Normalize();
            mRightSpeakerToLeftEar.Add(new WWFirCoefficient(rl.Length / SoundSpeed, rlN, gain * attenuationMagnitude / rl.Length, true));

            // 1本のレイがそれぞれのスピーカーリスナー組に入る。
            mRouteCount[0] = 1;
            mRouteCount[1] = 1;
        }
Пример #2
0
        private double CalcRouteDistance(WWRoom room, int speakerCh, WWRoute route, WWLineSegment lastSegment, Point3D hitPos)
        {
            var    speakerToHitPos = hitPos - room.SpeakerPos(speakerCh);
            double distance        = speakerToHitPos.Length;

            for (int i = 0; i < route.Count(); ++i)
            {
                var lineSegment = route.GetNth(i);
                distance += lineSegment.Length;
            }
            distance += lastSegment.Length;
            return(distance);
        }
Пример #3
0
        private double CalcReflectionGain(ReflectionType type, WWRoom room, int speakerCh, Point3D hitPos, Vector3D rayDir, Vector3D hitSurfaceNormal)
        {
            if (type == ReflectionType.Diffuse)
            {
                // Lambert's cosine law
                return(Vector3D.DotProduct(-rayDir, hitSurfaceNormal));
            }

            // specular
            var reflectionDir = SpecularReflection(rayDir, hitSurfaceNormal);
            var speakerDir    = room.SpeakerPos(speakerCh) - hitPos;

            speakerDir.Normalize();
            var dot = Vector3D.DotProduct(reflectionDir, speakerDir);

            return(Math.Pow(Saturate0to1(dot), SPECULAR_HARDNESS));
        }
Пример #4
0
        public void TraceAll(WWRoom room)
        {
            var sw = new Stopwatch();

            sw.Start();

            Parallel.For(0, 100, i => {
                for (int j = 0; j < 5000; ++j)
                {
                    Trace(room, WallReflectionType, 0);
                    Trace(room, WallReflectionType, 1);
                }
            });

            sw.Stop();
            Console.WriteLine("elapsed time={0}", sw.Elapsed);
        }
Пример #5
0
 public void SetRoom(WWRoom room)
 {
     mRoom = room;
 }
Пример #6
0
 private double CalcRouteDistance(WWRoom room, int speakerCh, WWRoute route, WWLineSegment lastSegment, Point3D hitPos)
 {
     var speakerToHitPos = hitPos - room.SpeakerPos(speakerCh);
     double distance = speakerToHitPos.Length;
     for (int i = 0; i < route.Count(); ++i) {
         var lineSegment = route.GetNth(i);
         distance += lineSegment.Length;
     }
     distance += lastSegment.Length;
     return distance;
 }
Пример #7
0
        private double CalcReflectionGain(ReflectionType type, WWRoom room, int speakerCh, Point3D hitPos, Vector3D rayDir, Vector3D hitSurfaceNormal)
        {
            if (type == ReflectionType.Diffuse) {
                // Lambert's cosine law
                return Vector3D.DotProduct(-rayDir, hitSurfaceNormal);
            }

            // specular
            var reflectionDir = SpecularReflection(rayDir, hitSurfaceNormal);
            var speakerDir = room.SpeakerPos(speakerCh) - hitPos;
            speakerDir.Normalize();
            var dot = Vector3D.DotProduct(reflectionDir, speakerDir);
            return Math.Pow(Saturate0to1(dot), SPECULAR_HARDNESS);
        }
Пример #8
0
        public void TraceAll(WWRoom room)
        {
            var sw = new Stopwatch();
            sw.Start();

            Parallel.For(0, 100 , i => {
                for (int j = 0; j < 5000; ++j) {
                    Trace(room, WallReflectionType, 0);
                    Trace(room, WallReflectionType, 1);
                }
            });

            sw.Stop();
            Console.WriteLine("elapsed time={0}", sw.Elapsed);
        }
Пример #9
0
        /// <summary>
        ///  スピーカーから耳に届く音がたどる経路を調べる。
        /// </summary>
        /// <param name="room"></param>
        /// <param name="earCh">耳 0:左耳, 1:右耳</param>
        public void Trace(WWRoom room, ReflectionType reflectionType, int earCh)
        {
            var route = new WWRoute(earCh);

            // 耳の位置
            var rayPos = room.ListenerEarPos(earCh);
            var earDir = room.ListenerEarDir(earCh);

            Vector3D rayDir = RayGen(earDir);
            //耳からrayが発射して、部屋の壁に当たる

            // 音が耳に向かう方向。
            Vector3D soundDir = -rayDir;
            var accumReflectionGain = new double[] {1.0, 1.0};

            for (int i = 0; i < MaxReflectionCount; ++i) {
                Point3D hitPos;
                Vector3D hitSurfaceNormal;
                double rayLength;
                if (!room.RayIntersection(rayPos, rayDir, out hitPos, out hitSurfaceNormal, out rayLength)) {
                    // 終わり。
                    break;
                }

                // 1.0 - 反射率の確率で、計算を打ち切る。
                // たとえば反射率0.8の壁にRayが10本入射すると、8本のRayが強度を100%保ったまま反射する。
                if (WallReflectionRatio < NextDouble()) {
                    break;
                }

                // スピーカーから耳への道のりを計算する。
                var lineSegment = new WWLineSegment(rayPos, rayDir, rayLength, 1.0f /* 仮 Intensity */ );

                {
                    int speakerCh = earCh;
                    var distance = CalcRouteDistance(room, speakerCh, route, lineSegment, hitPos);
                    double gain = CalcReflectionGain(reflectionType, room, speakerCh, hitPos, rayDir, hitSurfaceNormal);
                    accumReflectionGain[0] *= gain;
                    var coeffS = new WWFirCoefficient(distance / SoundSpeed, soundDir, accumReflectionGain[0] / distance, false);
                    lineSegment.Intensity = coeffS.Gain;

                    if (1.0 / distance < SMALL_GAIN_THRESHOLD) {
                        break;
                    }

                    if (SMALL_GAIN_THRESHOLD <= coeffS.Gain) {
                        StoreCoeff(earCh, earCh, coeffS);
                    }
                }

                {
                    int speakerCh = (earCh == 0) ? 1 : 0;
                    var distance = CalcRouteDistance(room, speakerCh, route, lineSegment, hitPos);
                    double gain = CalcReflectionGain(reflectionType, room, speakerCh, hitPos, rayDir, hitSurfaceNormal);
                    accumReflectionGain[1] *= gain;
                    var coeffD = new WWFirCoefficient(distance / SoundSpeed, soundDir, accumReflectionGain[1] / distance, false);

                    if (SMALL_GAIN_THRESHOLD <= coeffD.Gain) {
                        StoreCoeff(earCh, speakerCh, coeffD);
                    }
                }

                route.Add(lineSegment);
                rayPos = hitPos;

                // 反射後の出射方向rayDir
                switch (reflectionType) {
                case ReflectionType.Diffuse:
                    rayDir = RayGen(hitSurfaceNormal);
                    break;
                case ReflectionType.Specular:
                    rayDir = SpecularReflection(rayDir, hitSurfaceNormal);
                    break;
                default:
                    System.Diagnostics.Debug.Assert(false);
                    break;
                }
            }

            // routeの中に、1つもlineSegmentが入っていないことがある。
            mRouteList.Add(route);
            Interlocked.Increment(ref mRouteCount[earCh]);
        }
Пример #10
0
        /// <summary>
        /// 初期設定する
        /// </summary>
        /// <param name="room"></param>
        public void Start(WWRoom room)
        {
            var leftEarPos  = room.ListenerEarPos(0);
            var rightEarPos = room.ListenerEarPos(1);

            var leftSpeakerPos = room.SpeakerPos(0);
            var rightSpeakerPos = room.SpeakerPos(1);

            // 左スピーカーから左の耳に音が届く
            var ll = leftEarPos - leftSpeakerPos;
            var llN = ll;
            llN.Normalize();

            // エネルギーは、距離の2乗に反比例する
            // 振幅は、距離の1乗に反比例
            // ということにする。

            mLeftSpeakerToLeftEar.Add(new WWFirCoefficient(ll.Length / SoundSpeed, llN, 1.0 / ll.Length, true));

            // 右スピーカーから右の耳に音が届く
            var rr = rightEarPos - rightSpeakerPos;
            var rrN = rr;
            rrN.Normalize();
            mRightSpeakerToRightEar.Add(new WWFirCoefficient(rr.Length / SoundSpeed, rrN, 1.0 / rr.Length, true));

            double gain = 1.0;
            if (WallReflectionType == ReflectionType.Specular) {
                // なんとなく、高音は逆の耳に届きにくい感じ。
                gain = 1.0/1.414;
            }

            // 左スピーカーから右の耳に音が届く。
            // 振幅が-3dBくらいになる。
            double attenuationDecibel = -3.0;
            double attenuationMagnitude = Math.Pow(10.0, attenuationDecibel / 20.0);

            var lr = rightEarPos - leftSpeakerPos;
            var lrN = lr;
            lrN.Normalize();
            mLeftSpeakerToRightEar.Add(new WWFirCoefficient(lr.Length / SoundSpeed, lrN, gain * attenuationMagnitude / lr.Length, true));

            var rl = leftEarPos - rightSpeakerPos;
            var rlN = rl;
            rlN.Normalize();
            mRightSpeakerToLeftEar.Add(new WWFirCoefficient(rl.Length / SoundSpeed, rlN, gain * attenuationMagnitude / rl.Length, true));

            // 1本のレイがそれぞれのスピーカーリスナー組に入る。
            mRouteCount[0] = 1;
            mRouteCount[1] = 1;
        }
Пример #11
0
 public void SetRoom(WWRoom room)
 {
     mRoom = room;
 }
Пример #12
0
        /// <summary>
        ///  スピーカーから耳に届く音がたどる経路を調べる。
        /// </summary>
        /// <param name="room"></param>
        /// <param name="earCh">耳 0:左耳, 1:右耳</param>
        public void Trace(WWRoom room, ReflectionType reflectionType, int earCh)
        {
            var route = new WWRoute(earCh);

            // 耳の位置
            var rayPos = room.ListenerEarPos(earCh);
            var earDir = room.ListenerEarDir(earCh);

            Vector3D rayDir = RayGen(earDir);
            //耳からrayが発射して、部屋の壁に当たる

            // 音が耳に向かう方向。
            Vector3D soundDir            = -rayDir;
            var      accumReflectionGain = new double[] { 1.0, 1.0 };

            for (int i = 0; i < MaxReflectionCount; ++i)
            {
                Point3D  hitPos;
                Vector3D hitSurfaceNormal;
                double   rayLength;
                if (!room.RayIntersection(rayPos, rayDir, out hitPos, out hitSurfaceNormal, out rayLength))
                {
                    // 終わり。
                    break;
                }

                // 1.0 - 反射率の確率で、計算を打ち切る。
                // たとえば反射率0.8の壁にRayが10本入射すると、8本のRayが強度を100%保ったまま反射する。
                if (WallReflectionRatio < NextDouble())
                {
                    break;
                }

                // スピーカーから耳への道のりを計算する。
                var lineSegment = new WWLineSegment(rayPos, rayDir, rayLength, 1.0f /* 仮 Intensity */);

                {
                    int    speakerCh = earCh;
                    var    distance  = CalcRouteDistance(room, speakerCh, route, lineSegment, hitPos);
                    double gain      = CalcReflectionGain(reflectionType, room, speakerCh, hitPos, rayDir, hitSurfaceNormal);
                    accumReflectionGain[0] *= gain;
                    var coeffS = new WWFirCoefficient(distance / SoundSpeed, soundDir, accumReflectionGain[0] / distance, false);
                    lineSegment.Intensity = coeffS.Gain;

                    if (1.0 / distance < SMALL_GAIN_THRESHOLD)
                    {
                        break;
                    }

                    if (SMALL_GAIN_THRESHOLD <= coeffS.Gain)
                    {
                        StoreCoeff(earCh, earCh, coeffS);
                    }
                }

                {
                    int    speakerCh = (earCh == 0) ? 1 : 0;
                    var    distance  = CalcRouteDistance(room, speakerCh, route, lineSegment, hitPos);
                    double gain      = CalcReflectionGain(reflectionType, room, speakerCh, hitPos, rayDir, hitSurfaceNormal);
                    accumReflectionGain[1] *= gain;
                    var coeffD = new WWFirCoefficient(distance / SoundSpeed, soundDir, accumReflectionGain[1] / distance, false);

                    if (SMALL_GAIN_THRESHOLD <= coeffD.Gain)
                    {
                        StoreCoeff(earCh, speakerCh, coeffD);
                    }
                }

                route.Add(lineSegment);
                rayPos = hitPos;

                // 反射後の出射方向rayDir
                switch (reflectionType)
                {
                case ReflectionType.Diffuse:
                    rayDir = RayGen(hitSurfaceNormal);
                    break;

                case ReflectionType.Specular:
                    rayDir = SpecularReflection(rayDir, hitSurfaceNormal);
                    break;

                default:
                    System.Diagnostics.Debug.Assert(false);
                    break;
                }
            }

            // routeの中に、1つもlineSegmentが入っていないことがある。
            mRouteList.Add(route);
            Interlocked.Increment(ref mRouteCount[earCh]);
        }