Example #1
0
        public static byte[] Encode(short[] pcm, CriAdxParameters config)
        {
            var c                = config;
            int sampleCount      = pcm.Length + c.Padding;
            int samplesPerFrame  = (c.FrameSize - 2) * 2;
            int frameCount       = sampleCount.DivideByRoundUp(samplesPerFrame);
            int paddingRemaining = c.Padding;

            short[] coefs = c.Type == CriAdxType.Fixed ? Coefs[c.Filter] : CalculateCoefficients(500, c.SampleRate);

            var pcmBuffer   = new short[samplesPerFrame + 2];
            var adpcmBuffer = new byte[c.FrameSize];
            var adpcmOut    = new byte[frameCount * c.FrameSize];

            if (c.Version == 4 && c.Padding == 0)
            {
                pcmBuffer[0] = pcm[0];
                pcmBuffer[1] = pcm[0];
                c.History    = pcm[0];
            }

            for (int i = 0; i < frameCount; i++)
            {
                int samplesToCopy  = Math.Min(sampleCount - i * samplesPerFrame, samplesPerFrame);
                int pcmBufferStart = 2;
                if (paddingRemaining != 0)
                {
                    while (paddingRemaining > 0 && samplesToCopy > 0)
                    {
                        paddingRemaining--;
                        samplesToCopy--;
                        pcmBufferStart++;
                    }
                    if (samplesToCopy == 0)
                    {
                        continue;
                    }
                }
                Array.Copy(pcm, Math.Max(i * samplesPerFrame - c.Padding, 0), pcmBuffer, pcmBufferStart, samplesToCopy);
                Array.Clear(pcmBuffer, pcmBufferStart + samplesToCopy, samplesPerFrame - samplesToCopy - pcmBufferStart + 2);

                EncodeFrame(pcmBuffer, adpcmBuffer, coefs, samplesPerFrame, c.Type, c.Version);

                if (c.Type == CriAdxType.Fixed)
                {
                    adpcmBuffer[0] |= (byte)(c.Filter << 5);
                }

                Array.Copy(adpcmBuffer, 0, adpcmOut, i * c.FrameSize, c.FrameSize);
                pcmBuffer[0] = pcmBuffer[samplesPerFrame];
                pcmBuffer[1] = pcmBuffer[samplesPerFrame + 1];

                config.Progress?.ReportAdd(1);
            }

            return(adpcmOut);
        }
Example #2
0
        public static short[] Decode(byte[] adpcm, int sampleCount, CriAdxParameters config = null)
        {
            CriAdxParameters c  = config ?? new CriAdxParameters();
            int samplesPerFrame = (c.FrameSize - 2) * 2;

            short[][] coefs = c.Type == CriAdxType.Fixed ? Coefs : new[] { CalculateCoefficients(c.HighpassFrequency, c.SampleRate) };
            var       pcm   = new short[sampleCount];

            int hist1      = c.History;
            int hist2      = c.History;
            int frameCount = sampleCount.DivideByRoundUp(samplesPerFrame);

            int currentSample = 0;
            int startSample   = c.Padding > 0 ? c.Padding % samplesPerFrame : 0;
            int inIndex       = c.Padding / samplesPerFrame * c.FrameSize;

            for (int i = 0; i < frameCount; i++)
            {
                int   filterNum = GetHighNibble(adpcm[inIndex]) >> 1;
                short scale     = (short)((adpcm[inIndex] << 8 | adpcm[inIndex + 1]) & 0x1FFF);
                scale    = (short)(c.Type == CriAdxType.Exponential ? 1 << (12 - scale) : scale + 1);
                inIndex += 2 + startSample / 2;

                int samplesToRead = Math.Min(samplesPerFrame, sampleCount - currentSample);

                for (int s = startSample; s < samplesToRead; s++)
                {
                    int sample = s % 2 == 0 ? GetHighNibbleSigned(adpcm[inIndex]) : GetLowNibbleSigned(adpcm[inIndex++]);
                    if (c.Version == 4)
                    {
                        sample = scale * sample + ((hist1 * coefs[filterNum][0] + hist2 * coefs[filterNum][1]) >> 12);
                    }
                    else
                    {
                        sample = scale * sample + (hist1 * coefs[filterNum][0] >> 12) + (hist2 * coefs[filterNum][1] >> 12);
                    }

                    short finalSample = Clamp16(sample);

                    hist2 = hist1;
                    hist1 = finalSample;
                    pcm[currentSample++] = finalSample;
                }
                startSample = 0;
            }
            return(pcm);
        }