Files
deepdrft/DeepDrftContent/Processors/Opus/OggOpusConstants.cs
T
daniel-c-harvey 33d6f34d8a feature: Phase 18.1 — derive Opus 320 + seek-index sidecar at ingest
Background-job transcode (ffmpeg/libopus) after source store; pure C# Ogg
walker builds the 0.5s-bucketed granule→byte seek index + captures the
OpusHead/OpusTags setup header into a per-track sidecar in a new track-opus
vault. Best-effort, additive, regenerated on replace-audio.
2026-06-23 06:30:10 -04:00

51 lines
2.4 KiB
C#

namespace DeepDrftContent.Processors.Opus;
/// <summary>
/// Wire-format constants for the Ogg-Opus derived artifacts. Centralised so the seek-index codec,
/// the page walker, and the tests agree on one set of magic numbers.
/// </summary>
public static class OggOpusConstants
{
/// <summary>Opus granule positions are always sample counts at 48 kHz, regardless of input rate.</summary>
public const double OpusSampleRate = 48000.0;
/// <summary>One seek-index entry per this many seconds of audio (OQ7 — 0.5 s buckets).</summary>
public const double SeekBucketSeconds = 0.5;
/// <summary>The Ogg page capture pattern "OggS" — every page starts with these four bytes.</summary>
public static ReadOnlySpan<byte> CapturePattern => "OggS"u8;
/// <summary>Magic signature opening an OpusHead identification header packet.</summary>
public static ReadOnlySpan<byte> OpusHeadSignature => "OpusHead"u8;
/// <summary>Magic signature opening an OpusTags comment header packet.</summary>
public static ReadOnlySpan<byte> OpusTagsSignature => "OpusTags"u8;
/// <summary>
/// Fixed size of an Ogg page header before the segment table: capture(4) + version(1) +
/// header-type(1) + granulepos(8) + serial(4) + sequence(4) + checksum(4) + page-segments(1).
/// </summary>
public const int OggPageHeaderSize = 27;
/// <summary>Byte offset of the 64-bit granule position within an Ogg page header.</summary>
public const int GranulePositionOffset = 6;
/// <summary>Byte offset of the page-segment count (the segment-table length) within the header.</summary>
public const int PageSegmentCountOffset = 26;
/// <summary>Sentinel granule position for a page that ends mid-packet (no usable timestamp).</summary>
public const ulong NoGranulePosition = 0xFFFFFFFFFFFFFFFFUL;
/// <summary>Header size of the serialized seek-index blob: totalBytes(8) + duration(8) + count(4).</summary>
public const int SeekIndexHeaderSize = 20;
/// <summary>Size of one serialized seek point: granulepos(8) + byteOffset(8).</summary>
public const int SeekPointSize = 16;
/// <summary>Vault-resource extension for the Opus audio bytes.</summary>
public const string OpusExtension = ".opus";
/// <summary>Vault-resource extension for the combined setup-header + seek-index sidecar.</summary>
public const string SidecarExtension = ".opusidx";
}