// SPDX-License-Identifier: MIT #nullable disable using System.IO; using LibAtrac9.Utilities; namespace LibAtrac9 { /// /// Stores the configuration data needed to decode or encode an ATRAC9 stream. /// public class Atrac9Config { /// /// The 4-byte ATRAC9 configuration data. /// public byte[] ConfigData { get; } /// /// A 4-bit value specifying one of 16 sample rates. /// public int SampleRateIndex { get; } /// /// A 3-bit value specifying one of 6 substream channel mappings. /// public int ChannelConfigIndex { get; } /// /// An 11-bit value containing the average size of a single frame. /// public int FrameBytes { get; } /// /// A 2-bit value indicating how many frames are in each superframe. /// public int SuperframeIndex { get; } /// /// The channel mapping used by the ATRAC9 stream. /// public ChannelConfig ChannelConfig { get; } /// /// The total number of channels in the ATRAC9 stream. /// public int ChannelCount { get; } /// /// The sample rate of the ATRAC9 stream. /// public int SampleRate { get; } /// /// Indicates whether the ATRAC9 stream has a of 8 or above. /// public bool HighSampleRate { get; } /// /// The number of frames in each superframe. /// public int FramesPerSuperframe { get; } /// /// The number of samples in one frame as an exponent of 2. /// = 2^. /// public int FrameSamplesPower { get; } /// /// The number of samples in one frame. /// public int FrameSamples { get; } /// /// The number of bytes in one superframe. /// public int SuperframeBytes { get; } /// /// The number of samples in one superframe. /// public int SuperframeSamples { get; } /// /// Reads ATRAC9 configuration data and calculates the stream parameters from it. /// /// The processed ATRAC9 configuration. public Atrac9Config(byte[] configData) { if (configData == null || configData.Length != 4) { throw new InvalidDataException("Config data must be 4 bytes long"); } ReadConfigData(configData, out int a, out int b, out int c, out int d); SampleRateIndex = a; ChannelConfigIndex = b; FrameBytes = c; SuperframeIndex = d; ConfigData = configData; FramesPerSuperframe = 1 << SuperframeIndex; SuperframeBytes = FrameBytes << SuperframeIndex; ChannelConfig = Tables.ChannelConfig[ChannelConfigIndex]; ChannelCount = ChannelConfig.ChannelCount; SampleRate = Tables.SampleRates[SampleRateIndex]; HighSampleRate = SampleRateIndex > 7; FrameSamplesPower = Tables.SamplingRateIndexToFrameSamplesPower[SampleRateIndex]; FrameSamples = 1 << FrameSamplesPower; SuperframeSamples = FrameSamples * FramesPerSuperframe; } private static void ReadConfigData(byte[] configData, out int sampleRateIndex, out int channelConfigIndex, out int frameBytes, out int superframeIndex) { var reader = new BitReader(configData); int header = reader.ReadInt(8); sampleRateIndex = reader.ReadInt(4); channelConfigIndex = reader.ReadInt(3); int validationBit = reader.ReadInt(1); frameBytes = reader.ReadInt(11) + 1; superframeIndex = reader.ReadInt(2); if (header != 0xFE || validationBit != 0) { throw new InvalidDataException("ATRAC9 Config Data is invalid"); } } } }