Beispiel #1
0
        /// <summary>
        /// Converts 24-bit samples to the specified format, using the specified
        /// buffer. Each <see langword="int"/> in the specified buffer will be
        /// interpreted as 24-bit values, and any extra bits will be ignored.
        /// If <paramref name="target"/> is equal to <see cref="AudioBitDepth.Bits24"/>,
        /// no action is performed.
        /// </summary>
        protected static unsafe void ChangeBitDepth24(byte *outputPtr, AudioBitDepth target, byte channels, int *inputPtr)
        {
            switch (target)
            {
            case AudioBitDepth.Bits8: {
                // 24bit -> 8bit
                for (int j = 0; j < channels; j++)
                {
                    *(outputPtr + j) = (byte)(*(inputPtr + j) >> 16);
                }
                break;
            }

            case AudioBitDepth.Bits16: {
                // 24bit -> 16bit
                short *opBufSamplePtr = (short *)outputPtr;
                for (int j = 0; j < channels; j++)
                {
                    *(opBufSamplePtr + j) = (short)(*(inputPtr + j) >> 8);
                }
                break;
            }

            case AudioBitDepth.Bits32: {
                // 24bit -> 32bit
                int *opBufSamplePtr = (int *)outputPtr;
                for (int j = 0; j < channels; j++)
                {
                    *(opBufSamplePtr + j) = *(inputPtr + j) << 8;
                }
                break;
            }
            }
        }
Beispiel #2
0
 /// <summary>
 /// Initializes a new instance of the <see cref="SampleFormat"/> structure.
 /// </summary>
 /// <param name="bitDepth">The bit-depth (bits per a single sample in a channel).</param>
 /// <param name="channels">The amount of channels.</param>
 /// <param name="signed">Whether the audio is signed, that is, whether the sample can store negative values. By convention, only 8-bit audio samples are unsigned.</param>
 public SampleFormat(AudioBitDepth bitDepth, byte channels, bool signed)
 {
     BitDepth = bitDepth;
     Channels = channels;
     Signed   = signed;
     Size     = ChannelSize * channels;
 }
Beispiel #3
0
        /// <summary>
        /// Converts 16-bit samples to the specified format, using the specified
        /// buffer. If <paramref name="target"/> is equal to <see cref="AudioBitDepth.Bits16"/>,
        /// no action is performed.
        /// </summary>
        protected static unsafe void ChangeBitDepth(byte *outputPtr, AudioBitDepth target, byte channels, short *inputPtr)
        {
            switch (target)
            {
            case AudioBitDepth.Bits8: {
                // 16bit -> 8bit
                for (int j = 0; j < channels; j++)
                {
                    *(outputPtr + j) = (byte)(*(inputPtr + j) >> 8);
                }
                break;
            }

            case AudioBitDepth.Bits24: {
                // 16bit -> 24bit
                for (int j = 0; j < channels; j++)
                {
                    WriteInt24ToBuffer(outputPtr, j * 3, *(inputPtr + j) << 8);
                }
                break;
            }

            case AudioBitDepth.Bits32: {
                // 16bit -> 32bit
                int *opBufSamplePtr = (int *)outputPtr;
                for (int j = 0; j < channels; j++)
                {
                    *(opBufSamplePtr + j) = *(inputPtr + j) << 16;
                }
                break;
            }
            }
        }
Beispiel #4
0
        /// <summary>
        /// Reads a single channel from the specified sample in the specified format
        /// and returns a pointer to the first byte of the read sample.
        /// </summary>
        private unsafe byte *ReadChannel(int index, int channel, bool signed, AudioBitDepth bitDepth)
        {
            target.ReadSampleChannel(index, channel, buffer);

            fixed(byte *bufferPtr = buffer)
            {
                EnsureBufferFormat(bufferPtr, bitDepth, signed, 1);
                return(bufferPtr);
            }
        }
Beispiel #5
0
        /// <summary>
        /// Makes a single unsigned audio sample signed.
        /// </summary>
        /// <param name="sourcePtr">The pointer to the target sample.</param>
        /// <param name="format">The audio format of the sample.</param>
        protected unsafe static void MakeSigned(byte *sourcePtr, AudioBitDepth bitDepth, byte channels)
        {
            // To change the sign of an unsigned value: value - ((data type max value / 2) + 1)
            switch (bitDepth)
            {
            case AudioBitDepth.Bits8:
                for (int j = 0; j < channels; j++)
                {
                    byte rawSample = sourcePtr[j];

                    // Unsigned 8-bit -> Signed 8-bit
                    sbyte sample = (sbyte)(rawSample - 128);
                    rawSample    = unchecked ((byte)sample);
                    sourcePtr[j] = rawSample;
                }
                break;

            case AudioBitDepth.Bits16:
                for (int j = 0; j < channels; j++)
                {
                    // Unsigned 16-bit -> Signed 16-bit
                    ushort origSample = *((ushort *)sourcePtr + j);
                    short  sample     = (short)(origSample - 32768);
                    *((short *)sourcePtr + j) = sample;
                }
                break;

            case AudioBitDepth.Bits24:
                for (int j = 0; j < channels; j++)
                {
                    // Unsigned 24-bit -> Signed 24-bit
                    int byteAlignment = j * 3;
                    int origSample    = ToInt24(sourcePtr, byteAlignment);
                    int sample        = origSample - 8388608;

                    WriteInt24ToBuffer(sourcePtr, byteAlignment, sample);
                }
                break;

            case AudioBitDepth.Bits32:
                for (int j = 0; j < channels; j++)
                {
                    // Unsigned 32-bit -> Signed 32-bit
                    uint origSample = *((uint *)sourcePtr + j);
                    int  sample     = (int)(origSample - 2147483648);
                    *((int *)sourcePtr + j) = sample;
                }
                break;
            }
        }
Beispiel #6
0
        private unsafe void EnsureBufferFormat(byte *bufferPtr, AudioBitDepth bitDepth, bool signed, byte channels)
        {
            if (target.Format.BitDepth != bitDepth)
            {
                ChangeBitDepth(
                    bufferPtr,
                    channels,
                    target.Format.BitDepth,
                    bitDepth
                    );
            }

            if (target.Format.Signed && !signed)
            {
                MakeUnsigned(bufferPtr, bitDepth, channels);
            }
            else if (!target.Format.Signed && signed)
            {
                MakeSigned(bufferPtr, bitDepth, channels);
            }
        }
Beispiel #7
0
        /// <summary>
        /// Converts the specified samples to the specified target format.
        /// The specified buffer pointer must be large enough to hold both
        /// the input samples, and the converted output samples.
        /// </summary>
        protected static unsafe void ChangeBitDepth(byte *bufferPtr, byte channels, AudioBitDepth inputBitDepth, AudioBitDepth outputBitDepth)
        {
            // Convert the bit-depth
            //     We have to re-normalize the samples; from the source data type's min and max value,
            //     to the target data type's min and max values - this operation can be represented by
            //     the following formula:
            //        (value / max source data type value) * max target data type value
            //     For example, to convert a 16-bit sample 0x0E to a 32-bit sample:
            //        (14 / 32767) * 2147483647
            //     However, this approach, while the most obvious from a mathematical standpoint,
            //     uses floating-point math. This can be much slower than direct bit-manipulation.
            //     The code below will do the equivalent to the provided formula by using
            //     bit-manipulation operators, making the method much more performant.
            //
            //     By using bit-shifting, we do not have to change the sign of the samples
            //     which is useful for us as we convert the samples in several different passes.

            switch (inputBitDepth)
            {
            case AudioBitDepth.Bits8: {
                // 8 bit -> target bit depth
                byte[] samples = new byte[channels];

                fixed(byte *samplesPtr = samples)
                {
                    MemoryOperations.Copy(samplesPtr, bufferPtr, channels);
                    ChangeBitDepth(bufferPtr, outputBitDepth, channels, samplesPtr);
                }

                break;
            }

            case AudioBitDepth.Bits16: {
                // 16 bit -> target bit depth
                short[] samples = new short[channels];

                fixed(short *samplesPtr = samples)
                {
                    MemoryOperations.Copy((byte *)samplesPtr, bufferPtr, channels * sizeof(short));
                    ChangeBitDepth(bufferPtr, outputBitDepth, channels, samplesPtr);
                }

                break;
            }

            case AudioBitDepth.Bits24: {
                // 24 bit -> target bit depth
                int[] samples = new int[channels];

                for (int j = 0; j < channels; j++)
                {
                    samples[j] = ToInt24(bufferPtr, j * 3);
                }

                fixed(int *samplesPtr = samples)
                {
                    ChangeBitDepth24(bufferPtr, outputBitDepth, channels, samplesPtr);
                }

                break;
            }

            case AudioBitDepth.Bits32: {
                // 32 bit -> target bit depth
                int[] samples = new int[channels];

                fixed(int *samplesPtr = samples)
                {
                    MemoryOperations.Copy((byte *)samplesPtr, bufferPtr, channels * sizeof(int));
                    ChangeBitDepth(bufferPtr, outputBitDepth, channels, samplesPtr);
                }

                break;
            }
            }
        }