Document Audio Pipeline

This commit is contained in:
copecone committed 2026-10-15 16:17:12 +09:00
1 parent 011c749df4
commit 131fabdbe1
22 files changed
+634 -12

No files matched your search

+25
View File
@@ -11,19 +11,38 @@ namespace ADOFAIRenderer.Util.Audio.Clip;
/// </summary>
internal sealed class MemoryPCMReader : IPCMReader
{
/// <summary>Block arrays; an entry is set to null when the block is released.</summary>
private readonly float[]?[] _blocks;
/// <summary>Called with each released block (for example to uncount its memory in the store); may be null.</summary>
private readonly Action<float[]>? _onBlockReleased;
private int _releasedCount; // Blocks [0, _releasedCount) are released
/// <inheritdoc/>
public int Channels { get; }
/// <inheritdoc/>
public int SampleRate { get; }
/// <inheritdoc/>
public long TotalFrames { get; }
/// <summary>True: blocks are released as they are read.</summary>
public bool IsForwardOnly => true;
/// <inheritdoc/>
public long Position { get; private set; }
/// <summary>Frames per block (all blocks except the last).</summary>
public int FramesPerBlock { get; }
/// <param name="blocks">Interleaved blocks in frame order; the reader takes ownership of the arrays (the list is copied).</param>
/// <param name="framesPerBlock">Frames in every block except possibly the last (positive).</param>
/// <param name="channels">Channel count (positive).</param>
/// <param name="sampleRate">Sample rate in Hz.</param>
/// <param name="totalFrames">Frame count; the blocks must hold at least this many frames.</param>
/// <param name="onBlockReleased">Called with each block when it is released; may be null.</param>
public MemoryPCMReader(IReadOnlyList<float[]> blocks, int framesPerBlock, int channels, int sampleRate, long totalFrames,
Action<float[]>? onBlockReleased)
{
@@ -40,6 +59,8 @@ internal sealed class MemoryPCMReader : IPCMReader
TotalFrames = totalFrames;
}
/// <inheritdoc/>
/// <exception cref="InvalidOperationException"><paramref name="frame"/> lies in a block that was already released.</exception>
public void Seek(long frame)
{
if (frame < 0 || frame > TotalFrames) throw new ArgumentOutOfRangeException(nameof(frame));
@@ -48,6 +69,8 @@ internal sealed class MemoryPCMReader : IPCMReader
Position = frame;
}
/// <inheritdoc/>
/// <remarks>Blocks whose end the position has passed are released after each copy.</remarks>
public int Read(float[] buffer, int frameCount)
{
var total = (int)Math.Min(frameCount, TotalFrames - Position);
@@ -68,6 +91,7 @@ internal sealed class MemoryPCMReader : IPCMReader
return written;
}
/// <summary>Releases every block with an index below <paramref name="blockIndex"/> that is not released yet, in order.</summary>
private void ReleaseBlocksBefore(int blockIndex)
{
while (_releasedCount < blockIndex && _releasedCount < _blocks.Length)
@@ -79,5 +103,6 @@ internal sealed class MemoryPCMReader : IPCMReader
}
}
/// <summary>Releases every remaining block. Safe to call more than once.</summary>
public void Dispose() => ReleaseBlocksBefore(_blocks.Length);
}