SHA256
Document Audio Pipeline
This commit is contained in:
22 files changed
+634
-12
No files matched your search
@@ -2,29 +2,50 @@ using System;
|
||||
|
||||
namespace ADOFAIRenderer.Util.Audio;
|
||||
|
||||
/// <summary>
|
||||
/// Splits the audio sample stream into per-video-frame sample counts so that audio and video stay aligned without drift.
|
||||
///
|
||||
/// The frame rate is converted to an exact fraction Numerator / Denominator (<see cref="RationalUtil.Double2MaxPrecisionInt"/>).
|
||||
/// Frame k receives floor((k + 1) * sampleRate * Denominator / Numerator) - floor(k * sampleRate * Denominator / Numerator) samples:
|
||||
/// the remainder of each division is carried into the next frame, so the sum over any number of frames equals the exact
|
||||
/// sample count of that duration rounded down (for example 44100 Hz at 60 fps gives 735 every frame; at 144 fps three frames of 306
|
||||
/// are followed by one of 307, 306.25 on average).
|
||||
/// Used by the render thread only (RenderManager.WriteAudioForFrame, once per frame sent to the encoder).
|
||||
/// </summary>
|
||||
internal class AudioSyncCalculator
|
||||
{
|
||||
/// <summary>Audio sample rate in Hz (samples per channel per second).</summary>
|
||||
private readonly long _sampleRate;
|
||||
|
||||
/// <summary>Video frame rate as a fraction (frames per second = Numerator / Denominator).</summary>
|
||||
private readonly (long Numerator, long Denominator) _fpsRational;
|
||||
|
||||
/// <summary>Total samples handed out since construction or <see cref="Reset"/> (kept for debugging, not read).</summary>
|
||||
// ReSharper disable once NotAccessedField.Local
|
||||
private long _currentSample;
|
||||
|
||||
/// <summary>Remainder of the last division, in units of 1 / Numerator samples (0 ~ Numerator - 1).</summary>
|
||||
private long _remainder;
|
||||
|
||||
/// <param name="sampleRate">Audio sample rate in Hz.</param>
|
||||
/// <param name="fps">Video frame rate in frames per second (the encoded frame rate).</param>
|
||||
public AudioSyncCalculator(long sampleRate, double fps)
|
||||
{
|
||||
_sampleRate = sampleRate;
|
||||
_fpsRational = RationalUtil.Double2MaxPrecisionInt(fps);
|
||||
}
|
||||
|
||||
/// <summary>Restarts the sequence at frame 0 (the remainder is cleared).</summary>
|
||||
public void Reset()
|
||||
{
|
||||
_currentSample = 0;
|
||||
_remainder = 0;
|
||||
}
|
||||
|
||||
/// <summary>Returns the sample count (frames per channel) of the next video frame and advances to the following frame.</summary>
|
||||
public int GetNextFrameSamples()
|
||||
{
|
||||
// samplesNeeded = floor((sampleRate * Denominator + remainder) / Numerator); the new remainder carries the fraction.
|
||||
var numerator = _sampleRate * _fpsRational.Denominator + _remainder;
|
||||
var samplesNeeded = numerator / _fpsRational.Numerator;
|
||||
|
||||
|
||||
Reference in new issue
Block a user