コード例 #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
ファイル: WWCrossFeedFir.cs プロジェクト: kekyo/PlayPcmWin
        /// <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]);
        }
コード例 #3
0
ファイル: WWCrossFeedFir.cs プロジェクト: kekyo/PlayPcmWin
        /// <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;
        }
コード例 #4
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]);
        }