aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AudioTester/AudioTester.csproj2
-rw-r--r--AudioTester/Core/RenderStreamer.cs32
-rw-r--r--AudioTester/Program.cs88
-rw-r--r--AudioTester/RayRoomSettings.cs3
-rw-r--r--RayRoom.NAudio/AudioOut.cs95
-rw-r--r--RayRoom.NAudio/AudioSampler.cs46
-rw-r--r--RayRoom.NAudio/RayRoom.NAudioEngine.csproj17
-rw-r--r--RayRoom.sln8
-rw-r--r--RayRoom/Core/AudioSimulator.cs74
-rw-r--r--RayRoom/Core/AudioSource.cs23
-rw-r--r--RayRoom/Core/CastInfo.cs6
-rw-r--r--RayRoom/Core/Circle.cs2
-rw-r--r--RayRoom/Core/CollisionHelpers.cs23
-rw-r--r--RayRoom/Core/Ray.cs9
-rw-r--r--RayRoom/Core/RaySimulator.cs67
-rw-r--r--RayRoom/Core/ResultContainer.cs28
-rw-r--r--RayRoom/Core/Settings.cs7
-rw-r--r--RayRoom/Core/Utils.cs15
-rw-r--r--RayRoom/Structures/ShiftArray.cs26
19 files changed, 411 insertions, 160 deletions
diff --git a/AudioTester/AudioTester.csproj b/AudioTester/AudioTester.csproj
index fc07b92..5549d83 100644
--- a/AudioTester/AudioTester.csproj
+++ b/AudioTester/AudioTester.csproj
@@ -9,7 +9,6 @@
<ItemGroup>
<PackageReference Include="NAudio" Version="2.2.1" />
- <PackageReference Include="System.Drawing.Common" Version="7.0.0" />
</ItemGroup>
<ItemGroup>
<Content Include="Resources\*">
@@ -20,6 +19,7 @@
<None Remove="Resources\test.wav" />
</ItemGroup>
<ItemGroup>
+ <ProjectReference Include="..\RayRoom.NAudio\RayRoom.NAudioEngine.csproj" />
<ProjectReference Include="..\RayRoom\RayRoom.csproj" />
</ItemGroup>
</Project>
diff --git a/AudioTester/Core/RenderStreamer.cs b/AudioTester/Core/RenderStreamer.cs
index c7d2595..81be958 100644
--- a/AudioTester/Core/RenderStreamer.cs
+++ b/AudioTester/Core/RenderStreamer.cs
@@ -1,4 +1,5 @@
using NAudio.Wave;
+using RayRoom.Core;
namespace AudioTester.Core
{
@@ -6,37 +7,18 @@ namespace AudioTester.Core
{
public WaveFormat WaveFormat { get; }
- private const int ReadBufferSize = 1024;
- private int sample;
- private Random rand;
+ private ISampleHandler provider;
- private AudioFileReader streamReader;
- private ISampleProvider provider;
-
- public RenderStreamer()
+ public RenderStreamer(ISampleHandler provider)
{
- rand = new Random();
- WaveFormat = WaveFormat.CreateIeeeFloatWaveFormat(44100, 2);
- sample = 0;
-
- streamReader = new AudioFileReader(@"Resources\test.wav");
-
- provider = streamReader.ToSampleProvider();
+ this.provider = provider;
+
+ WaveFormat = WaveFormat.CreateIeeeFloatWaveFormat(44100, 1);
}
public int Read(float[] buffer, int offset, int count)
{
- int length = provider.Read(buffer, offset, count);
-
- Console.WriteLine("i: {0}; o:{1}", count, length);
-
- if (length < count)
- {
- streamReader.Position = 0;
- length += provider.Read(buffer, length, count - length);
- }
-
- return length;
+ return provider.WriteTo(buffer, offset, count);
}
}
}
diff --git a/AudioTester/Program.cs b/AudioTester/Program.cs
index 95d6049..c2a3a0b 100644
--- a/AudioTester/Program.cs
+++ b/AudioTester/Program.cs
@@ -1,47 +1,36 @@
using AudioTester.Core;
-using AudioTester.Core.Extensions;
+using NAudio.Mixer;
using NAudio.Wave;
using RayRoom.Core;
-using System.Drawing;
+using RayRoom.NAudioEngine;
using System.Numerics;
namespace AudioTester
{
internal class Program
{
- private const int width = 1280;
- private const int height = 720;
- private const float scale = 100;
-#pragma warning disable CA1416 // Проверка совместимости платформы
+ [STAThread]
static void Main(string[] args)
{
- AudioSimulator a = new AudioSimulator(new Settings(44100, 5, 330));
+ var settings = new Settings(44100, 100, 330, 100f);
+ RaySimulator simulator = new RaySimulator(settings);
- var array = a.Simulate(Vector2.Zero, 3600);
- var bitmap = new Bitmap(width, height);
+ var sampler = new AudioSampler(@".\Resources\test.wav", true);
- Matrix2x2 mat = new(Vector2.UnitX * scale, Vector2.UnitY * -scale);
-
- Pen foreground = new(Color.FromArgb(20, Color.White), 1);
-
- using (Graphics g = Graphics.FromImage(bitmap))
+ List<ICastObject> structures = new List<ICastObject>
{
- g.Clear(Color.Black);
-
- Vector2 offset = new(width / 2, height / 2);
- for (int i = 0; i < array.Length; i++)
- {
- g.DrawLine(foreground,
- (array[i].a * mat + offset).GetPoint(),
- (array[i].b * mat + offset).GetPoint());
- }
- }
-
- bitmap.Save($"bitmap.png");
-#pragma warning restore CA1416 // Проверка совместимости платформы
- return;
- var device = new RenderStreamer();
+ new AudioSource(new Vector2(0, 9), 10, sampler),
+ new Line(new Vector2(-2, 10), new Vector2(-2, -10)),
+ new Line(new Vector2(-1, 8), new Vector2(1, 8)),
+ new Line(new Vector2(2, 10), new Vector2(2, -10)),
+ new Line(new Vector2(-2, -10), new Vector2(2, -10)),
+ new Line(new Vector2(-2, 10), new Vector2(2, 10)),
+ };
+
+ var device = new AudioOut(settings);
+ device.Container = new ResultContainer(0, new AudioSourceCollision[0]);
+ Vector2 pos = new Vector2(0, 0);
using (var wo = new WasapiOut(NAudio.CoreAudioApi.AudioClientShareMode.Shared, 150))
{
wo.Init(device);
@@ -49,10 +38,45 @@ namespace AudioTester
while (wo.PlaybackState == PlaybackState.Playing)
{
- Thread.Sleep(100);
-
if (Console.KeyAvailable)
- wo.Stop();
+ {
+ var key = Console.ReadKey();
+
+ switch (key.Key)
+ {
+ case ConsoleKey.Q:
+ break;
+ case ConsoleKey.E:
+ break;
+ case ConsoleKey.W:
+ pos += new Vector2(0, 0.1f);
+ break;
+ case ConsoleKey.S:
+ pos += new Vector2(0, -0.1f);
+ break;
+ case ConsoleKey.A:
+ pos += new Vector2(-0.1f, 0);
+ break;
+ case ConsoleKey.D:
+ pos += new Vector2(0.1f, 0);
+ break;
+ case ConsoleKey.Escape:
+ wo.Stop();
+ break;
+ default:
+ break;
+ }
+ Console.CursorLeft = 0;
+ Console.CursorTop = 0;
+ Console.WriteLine(" {0} ", pos.ToString("0.00"));
+ }
+
+ var left = simulator.Simulate(structures, -Vector2.UnitX * 0.1f + pos, 0, 36);
+ var right = simulator.Simulate(structures, Vector2.UnitX * 0.1f + pos, 1, 36);
+
+ var container = new ResultContainer(36, left.distances.Concat(right.distances).ToArray());
+
+ device.Container = container;
}
}
}
diff --git a/AudioTester/RayRoomSettings.cs b/AudioTester/RayRoomSettings.cs
index 8b05bcd..5c2f25f 100644
--- a/AudioTester/RayRoomSettings.cs
+++ b/AudioTester/RayRoomSettings.cs
@@ -9,7 +9,8 @@ namespace AudioTester
{
return new Settings(format.SampleRate,
baseSettings.maxRayReflections,
- baseSettings.speedOfSound);
+ baseSettings.speedOfSound,
+ 5f);
}
}
}
diff --git a/RayRoom.NAudio/AudioOut.cs b/RayRoom.NAudio/AudioOut.cs
new file mode 100644
index 0000000..79a3288
--- /dev/null
+++ b/RayRoom.NAudio/AudioOut.cs
@@ -0,0 +1,95 @@
+using NAudio.Wave;
+using RayRoom.Core;
+using RayRoom.Structures;
+
+namespace RayRoom.NAudioEngine
+{
+ public class AudioOut : ISampleProvider
+ {
+ public WaveFormat WaveFormat { get; }
+
+ public ResultContainer Container
+ {
+ get => container;
+
+ set
+ {
+ updatedPosition = value;
+ }
+ }
+
+ private ResultContainer updatedPosition;
+
+ private ShiftArray<float> leftBuffer;
+ private ShiftArray<float> rightBuffer;
+ private Settings settings;
+
+ private Dictionary<ISampleHandler, List<AudioSourceCollision>> sources;
+ private ResultContainer container;
+
+ public AudioOut(Settings settings)
+ {
+ this.settings = settings;
+ sources = new Dictionary<ISampleHandler, List<AudioSourceCollision>>();
+ WaveFormat = WaveFormat.CreateIeeeFloatWaveFormat(settings.frequency, 2);
+
+ leftBuffer = new ShiftArray<float>((int)(settings.frequency * (settings.maxDistanceMeters / settings.speedOfSound + 1)));
+ rightBuffer = new ShiftArray<float>((int)(settings.frequency * (settings.maxDistanceMeters / settings.speedOfSound + 1)));
+ }
+
+ public int Read(float[] buffer, int offset, int count)
+ {
+ container = updatedPosition;
+
+ float velocity = 1f / container.countOfRays;
+
+ sources.Clear();
+
+ foreach (var collision in container.distances)
+ if (sources.ContainsKey(collision.source.Handler))
+ sources[collision.source.Handler].Add(collision);
+ else
+ sources.Add(collision.source.Handler, new List<AudioSourceCollision>(10) { collision });
+
+ foreach (var source in sources)
+ {
+ float[] samples = new float[count / 2];
+
+ int read = source.Key.WriteTo(samples, 0, count / 2);
+
+ foreach (var collision in source.Value)
+ {
+ int offsetSamples = settings.GetSamplesDelay(collision.distance) * 4;
+ Parallel.For(0, count / 2, i =>
+ {
+ if (collision.channel == 0)
+ leftBuffer[i + offsetSamples] += samples[i] * velocity * (collision.source.Loudness / MathF.Pow(collision.distance, 2));
+ else
+ rightBuffer[i + offsetSamples] += samples[i] * velocity * (collision.source.Loudness / MathF.Pow(collision.distance, 2));
+
+ });
+ }
+ }
+
+ Parallel.For(0, count, i =>
+ {
+ if (i % 2 == 0)
+ {
+ buffer[i] = leftBuffer[i / 2];
+ leftBuffer[i / 2] = 0;
+ }
+ else
+ {
+ buffer[i] = rightBuffer[(i - 1) / 2];
+ rightBuffer[(i - 1) / 2] = 0;
+ }
+
+ });
+
+ leftBuffer.Offset += count / 2;
+ rightBuffer.Offset += count / 2;
+
+ return count;
+ }
+ }
+}
diff --git a/RayRoom.NAudio/AudioSampler.cs b/RayRoom.NAudio/AudioSampler.cs
new file mode 100644
index 0000000..2aebcce
--- /dev/null
+++ b/RayRoom.NAudio/AudioSampler.cs
@@ -0,0 +1,46 @@
+using NAudio.Wave;
+using RayRoom.Core;
+
+namespace RayRoom.NAudioEngine
+{
+ public class AudioSampler : ISampleHandler, IDisposable
+ {
+ public bool Loop { get; set; }
+
+ private bool disposed;
+
+ private AudioFileReader reader;
+ private ISampleProvider provider;
+
+ public AudioSampler(string file, bool looping = false)
+ {
+ disposed = false;
+ reader = new AudioFileReader(file);
+ Loop = looping;
+
+ provider = reader.ToSampleProvider();
+ provider = provider.ToMono();
+ }
+
+ public int WriteTo(float[] buffer, int offset, int count)
+ {
+ if (disposed) throw new ObjectDisposedException("AudioSampler is disposed");
+
+ int length = provider.Read(buffer, offset, count);
+
+ if (Loop && length < count)
+ {
+ reader.Position = 0;
+ length += provider.Read(buffer, length, count - length);
+ }
+
+ return length;
+ }
+
+ public void Dispose()
+ {
+ reader.Close();
+ reader.Dispose();
+ }
+ }
+} \ No newline at end of file
diff --git a/RayRoom.NAudio/RayRoom.NAudioEngine.csproj b/RayRoom.NAudio/RayRoom.NAudioEngine.csproj
new file mode 100644
index 0000000..471fb68
--- /dev/null
+++ b/RayRoom.NAudio/RayRoom.NAudioEngine.csproj
@@ -0,0 +1,17 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+ <PropertyGroup>
+ <TargetFramework>net6.0</TargetFramework>
+ <ImplicitUsings>enable</ImplicitUsings>
+ <Nullable>enable</Nullable>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <PackageReference Include="NAudio" Version="2.2.1" />
+ </ItemGroup>
+
+ <ItemGroup>
+ <ProjectReference Include="..\RayRoom\RayRoom.csproj" />
+ </ItemGroup>
+
+</Project>
diff --git a/RayRoom.sln b/RayRoom.sln
index 3c6a15a..d5f1090 100644
--- a/RayRoom.sln
+++ b/RayRoom.sln
@@ -7,7 +7,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RayRoom", "RayRoom\RayRoom.
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AudioTester", "AudioTester\AudioTester.csproj", "{BDA8477C-5901-4849-98D7-134871412EF5}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RayRoom.Tests", "RayRoom.Tests\RayRoom.Tests.csproj", "{B077A864-8279-4237-858B-37AA5A66C10D}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RayRoom.Tests", "RayRoom.Tests\RayRoom.Tests.csproj", "{B077A864-8279-4237-858B-37AA5A66C10D}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RayRoom.NAudioEngine", "RayRoom.NAudio\RayRoom.NAudioEngine.csproj", "{114D04B9-EAE7-4969-87A0-5F4652B4B088}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -27,6 +29,10 @@ Global
{B077A864-8279-4237-858B-37AA5A66C10D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B077A864-8279-4237-858B-37AA5A66C10D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B077A864-8279-4237-858B-37AA5A66C10D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {114D04B9-EAE7-4969-87A0-5F4652B4B088}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {114D04B9-EAE7-4969-87A0-5F4652B4B088}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {114D04B9-EAE7-4969-87A0-5F4652B4B088}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {114D04B9-EAE7-4969-87A0-5F4652B4B088}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/RayRoom/Core/AudioSimulator.cs b/RayRoom/Core/AudioSimulator.cs
deleted file mode 100644
index c5a913c..0000000
--- a/RayRoom/Core/AudioSimulator.cs
+++ /dev/null
@@ -1,74 +0,0 @@
-using System.Numerics;
-
-namespace RayRoom.Core
-{
- public class AudioSimulator
- {
- private Settings simulationSettings;
-
- public AudioSimulator(Settings simulationSettings)
- {
- this.simulationSettings = simulationSettings;
- }
-
- public Line[] Simulate(Vector2 position, int count)
- {
- count += 1;
- Ray[] startupRays = new Ray[count];
- for (int i = 0; i < count; i++)
- {
- float angle = i / (float)count * MathF.PI * 2f;
- startupRays[i] = new Ray(position, UnitVectorFromAngle(angle));
- }
-
- List<ICastObject> structures = new List<ICastObject>
- {
- new Circle(new Vector2(0, -3), 2f),
- new Circle(new Vector2(5, 3), 2f),
- new Circle(new Vector2(-0.5f, 0.5f), 0.5f),
- new Line(new Vector2(-10, -10), new Vector2(0, 10)),
- new Line(new Vector2(5, 3), new Vector2(0, 10)),
- new Line(new Vector2(-10, -10), new Vector2(0, -3)),
- new Line(new Vector2(0, -3), new Vector2(5, 3)),
- };
-
- List<Ray> rays = new(startupRays);
-
- List<Line> output = new(count);
-
- int castCount = count * 10;
-
- while (rays.Count > 0 && castCount-- > 0)
- {
- var ray = rays[0];
-
- rays.Remove(ray);
-
- if (ray.bounces >= simulationSettings.maxRayReflections)
- continue;
-
- CastInfo closest = CastInfo.Default;
-
- foreach (var structure in structures)
- {
- if (structure.CastRay(ray, out CastInfo info))
- if (closest.distance > info.distance)
- closest = info;
- }
-
- if (closest.collided)
- {
- output.Add(new Line(ray.position, closest.point));
- rays.Add(new Ray(closest.point, ray.direction - 2 * Vector2.Dot(ray.direction, closest.normal) * closest.normal, closest.distance, ray.bounces + 1));
- }
- }
-
- return output.ToArray();
- }
-
- private Vector2 UnitVectorFromAngle(float angle)
- {
- return new Vector2(MathF.Cos(angle), MathF.Sin(angle));
- }
- }
-}
diff --git a/RayRoom/Core/AudioSource.cs b/RayRoom/Core/AudioSource.cs
index ff5766f..78401f5 100644
--- a/RayRoom/Core/AudioSource.cs
+++ b/RayRoom/Core/AudioSource.cs
@@ -4,29 +4,36 @@ namespace RayRoom.Core
{
public interface ISampleHandler
{
- int Read(float[] buffer, int offset, int count);
+ int WriteTo(float[] buffer, int offset, int count);
}
public class AudioSource : ICastObject
{
- public const float size = 1.0f;
+ public const float size = 1f;
public bool IsAudioSource => true;
+ public float Loudness => loudness;
+ public ISampleHandler Handler => handler;
private Circle source;
- private float strength;
+ private float loudness;
+ private ISampleHandler handler;
- public AudioSource(Vector2 position, float strength)
+ public AudioSource(Vector2 position, float loudness, ISampleHandler handler)
{
- source = new Circle(position, strength);
- this.strength = strength;
+ source = new Circle(position, size);
+ this.loudness = loudness;
+ this.handler = handler;
}
-
public bool CastRay(Ray ray, out CastInfo info)
{
- return source.CastRay(ray, out info);
+ var result = CollisionHelpers.RaycastRayToCircle(source, ray, out info);
+
+ info = new CastInfo(info.point, info.normal, info.distance, info.collided, this);
+
+ return result;
}
}
}
diff --git a/RayRoom/Core/CastInfo.cs b/RayRoom/Core/CastInfo.cs
index 9dde7e3..8b89886 100644
--- a/RayRoom/Core/CastInfo.cs
+++ b/RayRoom/Core/CastInfo.cs
@@ -8,15 +8,17 @@ namespace RayRoom.Core
public readonly Vector2 normal;
public readonly float distance;
public readonly bool collided;
+ public readonly ICastObject? castObject;
- public static CastInfo Default => new CastInfo(Vector2.Zero, Vector2.Zero, float.MaxValue, false);
+ public static CastInfo Default => new CastInfo(Vector2.Zero, Vector2.Zero, float.MaxValue, false, null);
- public CastInfo(Vector2 point, Vector2 normal, float distance, bool collided)
+ public CastInfo(Vector2 point, Vector2 normal, float distance, bool collided, ICastObject? castObject)
{
this.point = point;
this.normal = normal;
this.distance = distance;
this.collided = collided;
+ this.castObject = castObject;
}
public override string ToString()
diff --git a/RayRoom/Core/Circle.cs b/RayRoom/Core/Circle.cs
index 28aee45..cbb7424 100644
--- a/RayRoom/Core/Circle.cs
+++ b/RayRoom/Core/Circle.cs
@@ -17,7 +17,7 @@ namespace RayRoom.Core
public bool CastRay(Ray ray, out CastInfo info)
{
- return CollisionHelpers.RaycastRayToSphere(this, ray, out info);
+ return CollisionHelpers.RaycastRayToCircle(this, ray, out info);
}
}
} \ No newline at end of file
diff --git a/RayRoom/Core/CollisionHelpers.cs b/RayRoom/Core/CollisionHelpers.cs
index d509a0b..94102da 100644
--- a/RayRoom/Core/CollisionHelpers.cs
+++ b/RayRoom/Core/CollisionHelpers.cs
@@ -4,7 +4,7 @@ namespace RayRoom.Core
{
public static class CollisionHelpers
{
- private static float minimalThreshold = 0.001f;
+ public static float minimalThreshold = 0.001f;
public struct Distances
{
@@ -40,22 +40,28 @@ namespace RayRoom.Core
Vector2 normal = GetClosestNormal(a.direction, b.direction);
- info = new CastInfo(b.position + b.direction * v, normal, (v * b.direction).Length(), true);
+ info = new CastInfo(b.position + b.direction * v, normal, (v * b.direction).Length(), true, a);
return new Distances(u, v);
}
public static Distances TestSphereToRay(Circle a, Ray b, out CastInfo info)
{
+ info = CastInfo.Default;
+ Distances result = new Distances(0, 0);
+
+
Vector2 position = b.position - a.center;
+ if (position.LengthSquared() < a.radius * a.radius)
+ return result;
+
float vb = 2 * b.direction.X * position.X + 2 * b.direction.Y * position.Y;
float va = MathF.Pow(b.direction.X, 2) + MathF.Pow(b.direction.Y, 2);
float vc = MathF.Pow(position.X, 2) + MathF.Pow(position.Y, 2) - MathF.Pow(a.radius, 2);
float discr = MathF.Pow(vb, 2) - 4 * va * vc;
- Distances result;
if (discr >= 0)
{
@@ -71,14 +77,9 @@ namespace RayRoom.Core
Vector2 normal = (b.position + b.direction * distance - a.center) / a.radius * -1f;
- info = new CastInfo(b.position + b.direction * distance, normal, (b.direction * distance).Length(), true);
+ info = new CastInfo(b.position + b.direction * distance, normal, (b.direction * distance).Length(), true, a);
result = new Distances(t0, t1);
}
- else
- {
- info = CastInfo.Default;
- result = new Distances(0, 0);
- }
return result;
}
@@ -97,7 +98,7 @@ namespace RayRoom.Core
return n1;
}
- public static bool RaycastRayToSphere(Circle sphere, Ray b, out CastInfo info)
+ public static bool RaycastRayToCircle(Circle sphere, Ray b, out CastInfo info)
{
var distances = TestSphereToRay(sphere, b, out info);
@@ -112,7 +113,7 @@ namespace RayRoom.Core
public static bool RaycastRayToLine(Line aLine, Ray b, out CastInfo info)
{
- Ray a = new Ray(aLine.a, aLine.b - aLine.a);
+ Ray a = new(aLine.a, aLine.b - aLine.a);
var result = TestRays(a, b, out info);
diff --git a/RayRoom/Core/Ray.cs b/RayRoom/Core/Ray.cs
index 2650cec..75f3d97 100644
--- a/RayRoom/Core/Ray.cs
+++ b/RayRoom/Core/Ray.cs
@@ -2,7 +2,7 @@
namespace RayRoom.Core
{
- public class Ray
+ public class Ray : ICastObject
{
public readonly Vector2 position;
public readonly Vector2 direction;
@@ -17,6 +17,13 @@ namespace RayRoom.Core
this.bounces = bounces;
}
+ public bool IsAudioSource => false;
+
+ public bool CastRay(Ray ray, out CastInfo info)
+ {
+ return CollisionHelpers.RaycastRayToRay(this, ray, out info);
+ }
+
public override string? ToString()
{
return string.Format("pos:{0} dir:{1} dist:{2}", position.ToString(), direction.ToString(), distance);
diff --git a/RayRoom/Core/RaySimulator.cs b/RayRoom/Core/RaySimulator.cs
new file mode 100644
index 0000000..267f4c0
--- /dev/null
+++ b/RayRoom/Core/RaySimulator.cs
@@ -0,0 +1,67 @@
+using System.Numerics;
+
+namespace RayRoom.Core
+{
+ public class RaySimulator
+ {
+ private Settings simulationSettings;
+
+ public RaySimulator(Settings simulationSettings)
+ {
+ this.simulationSettings = simulationSettings;
+ }
+
+ public ResultContainer Simulate(List<ICastObject> structures, Vector2 position, int channel, int count)
+ {
+ count += 1;
+
+ Ray[] startupRays = new Ray[count];
+
+ for (int i = 0; i < count; i++)
+ {
+ float angle = i / (float)count * MathF.PI * 2f;
+ startupRays[i] = new Ray(position, UnitVectorFromAngle(angle));
+ }
+
+ List<Ray> rays = new(startupRays);
+
+ List<AudioSourceCollision> distances = new(count);
+
+ while (rays.Count > 0)
+ {
+ var ray = rays[0];
+
+ rays.Remove(ray);
+
+ if (ray.bounces >= simulationSettings.maxRayReflections)
+ continue;
+ if (ray.distance >= simulationSettings.maxDistanceMeters)
+ continue;
+
+ CastInfo closest = CastInfo.Default;
+
+ foreach (var structure in structures)
+ if (structure.CastRay(ray, out CastInfo info) & closest.distance > info.distance)
+ closest = info;
+
+ if (closest.collided)
+ {
+ if (closest.castObject == null)
+ throw new NullReferenceException("CastInfo collided but castObject is null");
+
+ if (closest.castObject.IsAudioSource)
+ distances.Add(new(closest.distance, (AudioSource)closest.castObject, channel));
+ else
+ rays.Add(new Ray(closest.point, ray.direction - 2 * Vector2.Dot(ray.direction, closest.normal) * closest.normal, closest.distance, ray.bounces + 1));
+ }
+ }
+
+ return new ResultContainer(count, distances.ToArray());
+ }
+
+ private Vector2 UnitVectorFromAngle(float angle)
+ {
+ return new Vector2(MathF.Cos(angle), MathF.Sin(angle));
+ }
+ }
+}
diff --git a/RayRoom/Core/ResultContainer.cs b/RayRoom/Core/ResultContainer.cs
new file mode 100644
index 0000000..adecfd7
--- /dev/null
+++ b/RayRoom/Core/ResultContainer.cs
@@ -0,0 +1,28 @@
+namespace RayRoom.Core
+{
+ public struct ResultContainer
+ {
+ public readonly int countOfRays;
+ public AudioSourceCollision[] distances;
+
+ public ResultContainer(int countOfRays, AudioSourceCollision[] distances)
+ {
+ this.countOfRays = countOfRays;
+ this.distances = distances;
+ }
+ }
+
+ public struct AudioSourceCollision
+ {
+ public readonly float distance;
+ public readonly AudioSource source;
+ public readonly int channel;
+
+ public AudioSourceCollision(float distance, AudioSource source, int channel)
+ {
+ this.distance = distance;
+ this.source = source;
+ this.channel = channel;
+ }
+ }
+}
diff --git a/RayRoom/Core/Settings.cs b/RayRoom/Core/Settings.cs
index 72eaebc..d970d21 100644
--- a/RayRoom/Core/Settings.cs
+++ b/RayRoom/Core/Settings.cs
@@ -5,14 +5,15 @@
public readonly int frequency;
public readonly int maxRayReflections;
public readonly float speedOfSound;
+ public readonly float maxDistanceMeters;
+ public static Settings Default => new Settings(44100, 10, 330f, 10f);
- public static Settings Default => new Settings(44100, 10, 330f);
-
- public Settings(int frequency, int maxRayReflections, float speedOfSound)
+ public Settings(int frequency, int maxRayReflections, float speedOfSound, float maxDistanceMeters)
{
this.frequency = frequency;
this.maxRayReflections = maxRayReflections;
this.speedOfSound = speedOfSound;
+ this.maxDistanceMeters = maxDistanceMeters;
}
public float GetSecoundsDelay(float distance)
diff --git a/RayRoom/Core/Utils.cs b/RayRoom/Core/Utils.cs
new file mode 100644
index 0000000..1561ac6
--- /dev/null
+++ b/RayRoom/Core/Utils.cs
@@ -0,0 +1,15 @@
+namespace RayRoom.Core
+{
+ public static class Utils
+ {
+ public static float VolumeToDB(float volume)
+ {
+ return 20 * MathF.Log10(volume);
+ }
+
+ public static float DBToVolume(float db)
+ {
+ return MathF.Pow(10f, db / 20f);
+ }
+ }
+}
diff --git a/RayRoom/Structures/ShiftArray.cs b/RayRoom/Structures/ShiftArray.cs
new file mode 100644
index 0000000..c837aa8
--- /dev/null
+++ b/RayRoom/Structures/ShiftArray.cs
@@ -0,0 +1,26 @@
+namespace RayRoom.Structures
+{
+ public class ShiftArray<T>
+ {
+ public T this[int index]
+ {
+ get
+ {
+ return items[(index + Offset) % items.Length];
+ }
+ set
+ {
+ items[(index + Offset) % items.Length] = value;
+ }
+ }
+
+ public int Offset { get; set; }
+
+ private T[] items;
+
+ public ShiftArray(int capacity)
+ {
+ items = new T[capacity];
+ }
+ }
+}