Example #1
0
        private static void ReadSpectralCoefficients(CriHcaFrame frame, BitReader reader)
        {
            for (int sf = 0; sf < SubframesPerFrame; sf++)
            {
                foreach (CriHcaChannel channel in frame.Channels)
                {
                    for (int s = 0; s < channel.CodedScaleFactorCount; s++)
                    {
                        int resolution = channel.Resolution[s];
                        int bits       = CriHcaTables.QuantizedSpectrumMaxBits[resolution];
                        int code       = reader.PeekInt(bits);
                        if (resolution < 8)
                        {
                            bits = CriHcaTables.QuantizedSpectrumBits[resolution][code];
                            channel.QuantizedSpectra[sf][s] = CriHcaTables.QuantizedSpectrumValue[resolution][code];
                        }
                        else
                        {
                            // Read the sign-magnitude value. The low bit is the sign
                            int quantizedCoefficient = code / 2 * (1 - (code % 2 * 2));
                            if (quantizedCoefficient == 0)
                            {
                                bits--;
                            }
                            channel.QuantizedSpectra[sf][s] = quantizedCoefficient;
                        }
                        reader.Position += bits;
                    }

                    Array.Clear(channel.Spectra[sf], channel.CodedScaleFactorCount, 0x80 - channel.CodedScaleFactorCount);
                }
            }
        }
Example #2
0
        private static void CalculateNoiseLevel(CriHcaFrame frame)
        {
            int highestBand   = frame.Hca.BaseBandCount + frame.Hca.StereoBandCount - 1;
            int availableBits = frame.Hca.FrameSize * 8;
            int maxLevel      = 255;
            int minLevel      = 0;
            int level         = BinarySearchLevel(frame.Channels, availableBits, minLevel, maxLevel);

            // If there aren't enough available bits, remove bands until there are.
            while (level < 0)
            {
                highestBand -= 2;
                if (highestBand < 0)
                {
                    throw new InvalidDataException("Bitrate is set too low.");
                }

                foreach (CriHcaChannel channel in frame.Channels)
                {
                    channel.ScaleFactors[highestBand + 1] = 0;
                    channel.ScaleFactors[highestBand + 2] = 0;
                }

                CalculateFrameHeaderLength(frame);
                level = BinarySearchLevel(frame.Channels, availableBits, minLevel, maxLevel);
            }

            frame.AcceptableNoiseLevel = level;
        }
Example #3
0
 private static void ApplyIntensityStereo(CriHcaFrame frame)
 {
     if (frame.Hca.StereoBandCount <= 0)
     {
         return;
     }
     for (int c = 0; c < frame.Channels.Length; c++)
     {
         if (frame.Channels[c].Type != ChannelType.StereoPrimary)
         {
             continue;
         }
         for (int sf = 0; sf < SubframesPerFrame; sf++)
         {
             double[] l      = frame.Channels[c].Spectra[sf];
             double[] r      = frame.Channels[c + 1].Spectra[sf];
             double   ratioL = IntensityRatioTable[frame.Channels[c + 1].Intensity[sf]];
             double   ratioR = ratioL - 2.0;
             for (int b = frame.Hca.BaseBandCount; b < frame.Hca.TotalBandCount; b++)
             {
                 r[b]  = l[b] * ratioR;
                 l[b] *= ratioL;
             }
         }
     }
 }
Example #4
0
        private static void EncodeIntensityStereo(CriHcaFrame frame)
        {
            if (frame.Hca.StereoBandCount <= 0)
            {
                return;
            }

            for (int c = 0; c < frame.Channels.Length; c++)
            {
                if (frame.Channels[c].Type != ChannelType.StereoPrimary)
                {
                    continue;
                }

                for (int sf = 0; sf < SubframesPerFrame; sf++)
                {
                    double[] l = frame.Channels[c].Spectra[sf];
                    double[] r = frame.Channels[c + 1].Spectra[sf];

                    double energyL     = 0;
                    double energyR     = 0;
                    double energyTotal = 0;

                    for (int b = frame.Hca.BaseBandCount; b < frame.Hca.TotalBandCount; b++)
                    {
                        energyL     += Math.Abs(l[b]);
                        energyR     += Math.Abs(r[b]);
                        energyTotal += Math.Abs(l[b] + r[b]);
                    }
                    energyTotal *= 2;

                    double energyLR    = energyR + energyL;
                    double storedValue = 2 * energyL / energyLR;
                    double energyRatio = energyLR / energyTotal;
                    energyRatio = Clamp(energyRatio, 0.5, Math.Sqrt(2) / 2);

                    int quantized = 1;
                    if (energyR > 0 || energyL > 0)
                    {
                        while (quantized < 13 && CriHcaTables.IntensityRatioBoundsTable[quantized] >= storedValue)
                        {
                            quantized++;
                        }
                    }
                    else
                    {
                        quantized   = 0;
                        energyRatio = 1;
                    }

                    frame.Channels[c + 1].Intensity[sf] = quantized;

                    for (int b = frame.Hca.BaseBandCount; b < frame.Hca.TotalBandCount; b++)
                    {
                        l[b] = (l[b] + r[b]) * energyRatio;
                        r[b] = 0;
                    }
                }
            }
        }
Example #5
0
 private static bool UnpackingWasSuccessful(CriHcaFrame frame, BitReader reader)
 {
     // 128 leftover bits after unpacking should be high enough to get rid of false negatives,
     // and low enough that false positives will be uncommon.
     return(reader.Remaining >= 16 && reader.Remaining <= 128 ||
            FrameEmpty(frame) ||
            frame.AcceptableNoiseLevel == 0 && reader.Remaining >= 16);
 }
Example #6
0
 public static bool UnpackFrame(CriHcaFrame frame, BitReader reader)
 {
     if (!UnpackFrameHeader(frame, reader))
     {
         return(false);
     }
     ReadSpectralCoefficients(frame, reader);
     return(UnpackingWasSuccessful(frame, reader));
 }
Example #7
0
        private static void DecodeFrame(byte[] audio, CriHcaFrame frame, short[][] pcmOut)
        {
            var reader = new BitReader(audio);

            UnpackFrame(frame, reader);
            DequantizeFrame(frame);
            RestoreMissingBands(frame);
            RunImdct(frame);
            PcmFloatToShort(frame, pcmOut);
        }
Example #8
0
 private static void RunImdct(CriHcaFrame frame)
 {
     for (int sf = 0; sf < SubframesPerFrame; sf++)
     {
         foreach (CriHcaChannel channel in frame.Channels)
         {
             channel.Mdct.RunImdct(channel.Spectra[sf], channel.PcmFloat[sf]);
         }
     }
 }
Example #9
0
        /// <summary>
        /// Initializes this <see cref="CriHcaEncoder"/>. Any preexisting state is reset, and the encoder
        /// will be ready to accept PCM audio via <see cref="Encode"/>.
        /// </summary>
        /// <param name="config">The configuration to be used when creating the HCA file.</param>
        public void Initialize(CriHcaParameters config)
        {
            if (config.ChannelCount > 8)
            {
                throw new ArgumentOutOfRangeException(nameof(config.ChannelCount), "HCA channel count must be 8 or below");
            }

            CutoffFrequency = config.SampleRate / 2;
            Quality         = config.Quality;
            PostSamples     = 128;

            Hca = new HcaInfo
            {
                ChannelCount    = config.ChannelCount,
                TrackCount      = 1,
                SampleCount     = config.SampleCount,
                SampleRate      = config.SampleRate,
                MinResolution   = 1,
                MaxResolution   = 15,
                InsertedSamples = SamplesPerSubFrame
            };

            Bitrate = CalculateBitrate(Hca, Quality, config.Bitrate, config.LimitBitrate);
            CalculateBandCounts(Hca, Bitrate, CutoffFrequency);
            Hca.CalculateHfrValues();
            SetChannelConfiguration(Hca);

            int inputSampleCount = Hca.SampleCount;

            if (config.Looping)
            {
                Hca.Looping          = true;
                Hca.SampleCount      = Math.Min(config.LoopEnd, config.SampleCount);
                Hca.InsertedSamples += GetNextMultiple(config.LoopStart, SamplesPerFrame) - config.LoopStart;
                CalculateLoopInfo(Hca, config.LoopStart, config.LoopEnd);
                inputSampleCount  = Math.Min(GetNextMultiple(Hca.SampleCount, SamplesPerSubFrame), config.SampleCount);
                inputSampleCount += SamplesPerSubFrame * 2;
                PostSamples       = inputSampleCount - Hca.SampleCount;
            }

            CalculateHeaderSize(Hca);

            int totalSamples = inputSampleCount + Hca.InsertedSamples;

            Hca.FrameCount      = totalSamples.DivideByRoundUp(SamplesPerFrame);
            Hca.AppendedSamples = Hca.FrameCount * SamplesPerFrame - Hca.InsertedSamples - inputSampleCount;

            Frame            = new CriHcaFrame(Hca);
            Channels         = Frame.Channels;
            PcmBuffer        = CreateJaggedArray <short[][]>(Hca.ChannelCount, SamplesPerFrame);
            PostAudio        = CreateJaggedArray <short[][]>(Hca.ChannelCount, PostSamples);
            HcaOutputBuffer  = new Queue <byte[]>();
            BufferPreSamples = Hca.InsertedSamples - 128;
        }
Example #10
0
 private static void PcmFloatToShort(CriHcaFrame frame, short[][] pcm)
 {
     for (int c = 0; c < frame.Channels.Length; c++)
     {
         for (int sf = 0; sf < SubframesPerFrame; sf++)
         {
             for (int s = 0; s < SamplesPerSubFrame; s++)
             {
                 int sample = (int)(frame.Channels[c].PcmFloat[sf][s] * (short.MaxValue + 1));
                 pcm[c][sf * SamplesPerSubFrame + s] = Helpers.Clamp16(sample);
             }
         }
     }
 }
Example #11
0
        public static CriHcaKey FindKey(HcaInfo hca, byte[][] audio)
        {
            var frame  = new CriHcaFrame(hca);
            var buffer = new byte[hca.FrameSize];

            foreach (CriHcaKey key in Keys)
            {
                if (TestKey(frame, audio, key, buffer))
                {
                    return(key);
                }
            }
            return(null);
        }
Example #12
0
 private static void CalculateFrameHeaderLength(CriHcaFrame frame)
 {
     foreach (CriHcaChannel channel in frame.Channels)
     {
         CalculateOptimalDeltaLength(channel);
         if (channel.Type == ChannelType.StereoSecondary)
         {
             channel.HeaderLengthBits += 32;
         }
         else if (frame.Hca.HfrGroupCount > 0)
         {
             channel.HeaderLengthBits += 6 * frame.Hca.HfrGroupCount;
         }
     }
 }
Example #13
0
        private static void CalculateEvaluationBoundary(CriHcaFrame frame)
        {
            if (frame.AcceptableNoiseLevel == 0)
            {
                frame.EvaluationBoundary = 0;
                return;
            }

            int availableBits = frame.Hca.FrameSize * 8;
            int maxLevel      = 127;
            int minLevel      = 0;
            int level         = BinarySearchBoundary(frame.Channels, availableBits, frame.AcceptableNoiseLevel, minLevel, maxLevel);

            frame.EvaluationBoundary = level >= 0 ? level : throw new NotImplementedException();
        }
Example #14
0
 private static void CalculateFrameResolutions(CriHcaFrame frame)
 {
     foreach (CriHcaChannel channel in frame.Channels)
     {
         for (int i = 0; i < frame.EvaluationBoundary; i++)
         {
             channel.Resolution[i] = CalculateResolution(channel.ScaleFactors[i], frame.AcceptableNoiseLevel - 1);
         }
         for (int i = frame.EvaluationBoundary; i < channel.CodedScaleFactorCount; i++)
         {
             channel.Resolution[i] = CalculateResolution(channel.ScaleFactors[i], frame.AcceptableNoiseLevel);
         }
         Array.Clear(channel.Resolution, channel.CodedScaleFactorCount, channel.Resolution.Length - channel.CodedScaleFactorCount);
     }
 }
Example #15
0
        private static bool TestKey(CriHcaFrame frame, byte[][] audio, CriHcaKey key, byte[] buffer)
        {
            int startFrame = FindFirstNonEmptyFrame(audio);
            int endFrame   = Math.Min(audio.Length, startFrame + FramesToTest);

            for (int i = startFrame; i < endFrame; i++)
            {
                Array.Copy(audio[i], buffer, audio[i].Length);
                CryptFrame(frame.Hca, buffer, key, true);
                var reader = new BitReader(buffer);
                if (!CriHcaPacking.UnpackFrame(frame, reader))
                {
                    return(false);
                }
            }
            return(true);
        }
Example #16
0
        private static bool FrameEmpty(CriHcaFrame frame)
        {
            if (frame.AcceptableNoiseLevel > 0)
            {
                return(false);
            }

            // If all the scale factors are 0, the frame is empty
            foreach (CriHcaChannel channel in frame.Channels)
            {
                if (channel.ScaleFactorDeltaBits > 0)
                {
                    return(false);
                }
            }
            return(true);
        }
Example #17
0
        private static void CalculateHfrScale(CriHcaFrame frame)
        {
            HcaInfo hca = frame.Hca;

            if (hca.HfrGroupCount == 0)
            {
                return;
            }

            int hfrStartBand = hca.StereoBandCount + hca.BaseBandCount;
            int hfrBandCount = Math.Min(hca.HfrBandCount, hca.TotalBandCount - hca.HfrBandCount);

            foreach (CriHcaChannel channel in frame.Channels)
            {
                if (channel.Type == ChannelType.StereoSecondary)
                {
                    continue;
                }

                double[] groupSpectra = channel.HfrGroupAverageSpectra;

                for (int group = 0, band = 0; group < hca.HfrGroupCount; group++)
                {
                    double sum   = 0.0;
                    int    count = 0;

                    for (int i = 0; i < hca.BandsPerHfrGroup && band < hfrBandCount; band++, i++)
                    {
                        for (int subframe = 0; subframe < SubframesPerFrame; subframe++)
                        {
                            sum += Math.Abs(channel.ScaledSpectra[hfrStartBand - band - 1][subframe]);
                        }
                        count += SubframesPerFrame;
                    }

                    double averageSpectra = sum / count;
                    if (averageSpectra > 0.0)
                    {
                        groupSpectra[group] *= Math.Min(1.0 / averageSpectra, Math.Sqrt(2));
                    }

                    channel.HfrScales[group] = FindScaleFactor(groupSpectra[group]);
                }
            }
        }
Example #18
0
        private static void DequantizeFrame(CriHcaFrame frame)
        {
            foreach (CriHcaChannel channel in frame.Channels)
            {
                CalculateGain(channel);
            }

            for (int sf = 0; sf < SubframesPerFrame; sf++)
            {
                foreach (CriHcaChannel channel in frame.Channels)
                {
                    for (int s = 0; s < channel.CodedScaleFactorCount; s++)
                    {
                        channel.Spectra[sf][s] = channel.QuantizedSpectra[sf][s] * channel.Gain[s];
                    }
                }
            }
        }
Example #19
0
        public static short[][] Decode(HcaInfo hca, byte[][] audio, CriHcaParameters config = null)
        {
            config?.Progress?.SetTotal(hca.FrameCount);
            var pcmOut    = Helpers.CreateJaggedArray <short[][]>(hca.ChannelCount, hca.SampleCount);
            var pcmBuffer = Helpers.CreateJaggedArray <short[][]>(hca.ChannelCount, SamplesPerFrame);

            var frame = new CriHcaFrame(hca);

            for (int i = 0; i < hca.FrameCount; i++)
            {
                DecodeFrame(audio[i], frame, pcmBuffer);

                CopyPcmToOutput(pcmBuffer, pcmOut, hca, i);
                //CopyBuffer(pcmBuffer, pcmOut, hca.InsertedSamples, i);
                config?.Progress?.ReportAdd(1);
            }

            return(pcmOut);
        }
Example #20
0
        public static void PackFrame(CriHcaFrame frame, Crc16 crc, byte[] outBuffer)
        {
            var writer = new BitWriter(outBuffer);

            writer.Write(0xffff, 16);
            writer.Write(frame.AcceptableNoiseLevel, 9);
            writer.Write(frame.EvaluationBoundary, 7);

            foreach (CriHcaChannel channel in frame.Channels)
            {
                WriteScaleFactors(writer, channel);
                if (channel.Type == ChannelType.StereoSecondary)
                {
                    for (int i = 0; i < SubframesPerFrame; i++)
                    {
                        writer.Write(channel.Intensity[i], 4);
                    }
                }
                else if (frame.Hca.HfrGroupCount > 0)
                {
                    for (int i = 0; i < frame.Hca.HfrGroupCount; i++)
                    {
                        writer.Write(channel.HfrScales[i], 6);
                    }
                }
            }

            for (int sf = 0; sf < SubframesPerFrame; sf++)
            {
                foreach (CriHcaChannel channel in frame.Channels)
                {
                    WriteSpectra(writer, channel, sf);
                }
            }

            writer.AlignPosition(8);
            for (int i = writer.Position / 8; i < frame.Hca.FrameSize - 2; i++)
            {
                writer.Buffer[i] = 0;
            }

            WriteChecksum(writer, crc, outBuffer);
        }
Example #21
0
        private static bool UnpackFrameHeader(CriHcaFrame frame, BitReader reader)
        {
            int syncWord = reader.ReadInt(16);

            if (syncWord != 0xffff)
            {
                throw new InvalidDataException("Invalid frame header");
            }

            byte[] athCurve = frame.AthCurve;
            frame.AcceptableNoiseLevel = reader.ReadInt(9);
            frame.EvaluationBoundary   = reader.ReadInt(7);

            foreach (CriHcaChannel channel in frame.Channels)
            {
                if (!ReadScaleFactors(channel, reader))
                {
                    return(false);
                }

                for (int i = 0; i < frame.EvaluationBoundary; i++)
                {
                    channel.Resolution[i] = CalculateResolution(channel.ScaleFactors[i], athCurve[i] + frame.AcceptableNoiseLevel - 1);
                }

                for (int i = frame.EvaluationBoundary; i < channel.CodedScaleFactorCount; i++)
                {
                    channel.Resolution[i] = CalculateResolution(channel.ScaleFactors[i], athCurve[i] + frame.AcceptableNoiseLevel);
                }

                if (channel.Type == ChannelType.StereoSecondary)
                {
                    ReadIntensity(reader, channel.Intensity);
                }
                else if (frame.Hca.HfrGroupCount > 0)
                {
                    ReadHfrScaleFactors(reader, frame.Hca.HfrGroupCount, channel.HfrScales);
                }
            }
            return(true);
        }
Example #22
0
        private static void ReconstructHighFrequency(CriHcaFrame frame)
        {
            HcaInfo hca = frame.Hca;

            if (hca.HfrGroupCount == 0)
            {
                return;
            }

            // The last spectral coefficient should always be 0;
            int totalBandCount = Math.Min(hca.TotalBandCount, 127);

            int hfrStartBand = hca.BaseBandCount + hca.StereoBandCount;
            int hfrBandCount = Math.Min(hca.HfrBandCount, totalBandCount - hca.HfrBandCount);

            foreach (CriHcaChannel channel in frame.Channels)
            {
                if (channel.Type == ChannelType.StereoSecondary)
                {
                    continue;
                }

                for (int group = 0, band = 0; group < hca.HfrGroupCount; group++)
                {
                    for (int i = 0; i < hca.BandsPerHfrGroup && band < hfrBandCount; band++, i++)
                    {
                        int highBand = hfrStartBand + band;
                        int lowBand  = hfrStartBand - band - 1;
                        int index    = channel.HfrScales[group] - channel.ScaleFactors[lowBand] + 64;
                        for (int sf = 0; sf < SubframesPerFrame; sf++)
                        {
                            channel.Spectra[sf][highBand] = ScaleConversionTable[index] * channel.Spectra[sf][lowBand];
                        }
                    }
                }
            }
        }
Example #23
0
        private static void CalculateHfrGroupAverages(CriHcaFrame frame)
        {
            HcaInfo hca = frame.Hca;

            if (hca.HfrGroupCount == 0)
            {
                return;
            }

            int hfrStartBand = hca.StereoBandCount + hca.BaseBandCount;

            foreach (CriHcaChannel channel in frame.Channels)
            {
                if (channel.Type == ChannelType.StereoSecondary)
                {
                    continue;
                }

                for (int group = 0, band = hfrStartBand; group < hca.HfrGroupCount; group++)
                {
                    double sum   = 0.0;
                    int    count = 0;

                    for (int i = 0; i < hca.BandsPerHfrGroup && band < SamplesPerSubFrame; band++, i++)
                    {
                        for (int subframe = 0; subframe < SubframesPerFrame; subframe++)
                        {
                            sum += Math.Abs(channel.Spectra[subframe][band]);
                        }
                        count += SubframesPerFrame;
                    }

                    channel.HfrGroupAverageSpectra[group] = sum / count;
                }
            }
        }
Example #24
0
 private static void RestoreMissingBands(CriHcaFrame frame)
 {
     ReconstructHighFrequency(frame);
     ApplyIntensityStereo(frame);
 }