Attempting to generate sound, and set cells automatically

This commit is contained in:
max
2026-05-02 23:26:52 +02:00
parent 2c338ad7d9
commit a262410616
16 changed files with 442 additions and 285 deletions

41
Audio/RingBuffer.cs Normal file
View File

@@ -0,0 +1,41 @@
namespace FluidSim.Audio
{
internal class RingBuffer
{
private readonly float[] buffer;
private volatile int readPos;
private volatile int writePos;
public RingBuffer(int capacity)
{
if ((capacity & (capacity - 1)) != 0)
throw new ArgumentException("Capacity must be a power of two.");
buffer = new float[capacity];
}
public int Count => (writePos - readPos) & (buffer.Length - 1);
public int Space => (readPos - writePos - 1) & (buffer.Length - 1);
public int Write(float[] data, int count)
{
int space = Space;
int toWrite = Math.Min(count, space);
int mask = buffer.Length - 1;
for (int i = 0; i < toWrite; i++)
buffer[(writePos + i) & mask] = data[i];
writePos = (writePos + toWrite) & mask;
return toWrite;
}
public int Read(float[] destination, int count)
{
int available = Count;
int toRead = Math.Min(count, available);
int mask = buffer.Length - 1;
for (int i = 0; i < toRead; i++)
destination[i] = buffer[(readPos + i) & mask];
readPos = (readPos + toRead) & mask;
return toRead;
}
}
}

43
Audio/RingBufferStream.cs Normal file
View File

@@ -0,0 +1,43 @@
using SFML.Audio;
using SFML.System;
namespace FluidSim.Audio
{
internal class RingBufferStream : SoundStream
{
private readonly RingBuffer ringBuffer;
public RingBufferStream(RingBuffer buffer)
{
ringBuffer = buffer;
// 2 channels, 44.1 kHz, standard stereo mapping
Initialize(2, 44100, new[] { SoundChannel.FrontLeft, SoundChannel.FrontRight });
}
protected override bool OnGetData(out short[] samples)
{
const int monoBlockSize = 512; // number of mono samples we'll read
float[] temp = new float[monoBlockSize];
int read = ringBuffer.Read(temp, monoBlockSize);
samples = new short[monoBlockSize * 2];
if (read > 0)
{
for (int i = 0; i < read; i++)
{
float clamped = Math.Clamp(temp[i], -1f, 1f);
short final = (short)(clamped * short.MaxValue);
samples[i * 2] = final; // left
samples[i * 2 + 1] = final; // right
}
}
for (int i = read * 2; i < samples.Length; i++)
samples[i] = 0;
return true;
}
protected override void OnSeek(Time timeOffset) =>
throw new NotSupportedException();
}
}

45
Audio/SoundEngine.cs Normal file
View File

@@ -0,0 +1,45 @@
namespace FluidSim.Audio;
public class SoundEngine : IDisposable
{
private readonly RingBuffer ringBuffer;
private readonly RingBufferStream stream;
private bool isPlaying;
public SoundEngine(int bufferCapacity = 16384)
{
ringBuffer = new RingBuffer(bufferCapacity);
stream = new RingBufferStream(ringBuffer);
}
public void Start()
{
if (isPlaying) return;
stream.Play();
isPlaying = true;
}
public void Stop()
{
if (!isPlaying) return;
stream.Stop();
isPlaying = false;
float[] drain = new float[ringBuffer.Count];
ringBuffer.Read(drain, drain.Length);
}
public int WriteSamples(float[] data, int count) =>
ringBuffer.Write(data, count);
public float Volume
{
get => stream.Volume;
set => stream.Volume = value;
}
public void Dispose()
{
Stop();
stream.Dispose();
}
}

29
Audio/SoundProcessor.cs Normal file
View File

@@ -0,0 +1,29 @@
using FluidSim.Components;
using FluidSim.Interfaces;
using System;
namespace FluidSim.Audio
{
public static class SoundProcessor
{
public static float MaxDeltaP { get; set; } = 100_000f;
public static float MaxArea { get; set; } = 1e-4f;
public static float MaxVelocity { get; set; } = 343f;
public static float ReferenceDensity { get; set; } = 1.225f;
public static float ReferenceSpeedOfSound { get; set; } = 343f;
public static float Gain { get; set; } = 1.0f;
public static double ComputeSample(Connection conn)
{
Port portA = conn.PortA;
Port portB = conn.PortB;
double pressureUp = portA.Pressure;
double pressureDown = portB.Pressure;
// No flow or no pressure drop → silence
double deltaP = pressureUp - pressureDown;
return deltaP / 1;
}
}
}