예제 #1
0
        ////------------------------------------------------------------------------------------------------------------------------------
        public static FlacResidual Read(StreamBuffer sb, int blockSize, int order)
        {
            FlacResidual residual = new FlacResidual { _values = sb.ReadByte() };
            int partitions = 1 << residual.PartitionOrder;
            residual.RicePartitions = new FlacRicePartition[partitions];
            for (int i = 0; i < partitions; i++)
                residual.RicePartitions[i] = FlacRicePartition.Read(sb, i, residual.PartitionOrder, order, blockSize, residual.CodingMethod);

            return residual;
        }
예제 #2
0
        /// <summary>
        /// Initializes a new instance of the <see cref="XingHeader"/> class.
        /// </summary>
        /// <param name="firstFrame">The first frame.</param>
        /// <param name="firstFrameBuffer">The first frame buffer.</param>
        /// <param name="offset">The offset.</param>
        public XingHeader(MpaFrame firstFrame, StreamBuffer firstFrameBuffer, long offset)
            : base(firstFrame, firstFrameBuffer, offset, VbrHeaderType.Xing)
        {
            /*
            XING VBR-Header
            size    description
            4       'Xing' or 'Info'
            4       flags (indicates which fields are used)
            4       frames (optional)
            4       bytes (optional)
            100     toc (optional)
            4       a VBR quality indicator: 0=best 100=worst (optional)
            --------- +
            120 bytes
            *
            * NOTE: the frames (frameCount) in the XING header does not include its own frame.
            * So the total frames is actually XING framecount + 1
            */

            // name of the tag as found in the file
            Name = firstFrameBuffer.ReadString(4);

            // The flags indicate which fields are used in the XING header
            Flags = firstFrameBuffer.ReadBigEndianInt32();

            // Extract total frames in the file (XING header excludes it's own frame)
            if ((Flags & XingHeaderFlags.FrameCountFlag) != 0)
                FrameCount = firstFrameBuffer.ReadBigEndianInt32();

            // Extract size of the file, in bytes
            if ((Flags & XingHeaderFlags.FileSizeFlag) != 0)
                FileSize = firstFrameBuffer.ReadBigEndianInt32();

            // Extract TOC (Table of Contents) for more accurate seeking
            if ((Flags & XingHeaderFlags.TocFlag) != 0)
            {
                Toc = new int[100];
                for (int i = 0; i < 100; i++)
                    Toc[i] = firstFrameBuffer.ReadByte();
            }

            if ((Flags & XingHeaderFlags.VbrScaleFlag) != 0)
                Quality = firstFrameBuffer.ReadBigEndianInt32();

            // The LAME tag is always 120 bytes after the XING header - regardless of which fields are used
            LameTag = LameTag.FindTag(firstFrameBuffer, offset + 120);
        }
예제 #3
0
        private static ApeHeader ReadHeader(StreamBuffer stream, long startHeaderPosition, long endHeaderPosition)
        {
            if (stream == null)
                throw new ArgumentNullException("stream");

            stream.Position = startHeaderPosition;
            while (startHeaderPosition < endHeaderPosition)
            {
                int y = 0;
                while (stream.ReadByte() == TagIdentifierBytes[y++])
                {
                    startHeaderPosition++;
                    if (y != TagIdentifierBytes.Length)
                        continue;

                    ApeHeader hdr = new ApeHeader
                    {
                        Position = stream.Position - TagIdentifierBytes.Length,
                        Version = (ApeVersion)(stream.ReadLittleEndianInt32() / 1000),
                        Size = stream.ReadLittleEndianInt32(),
                        FrameCount = stream.ReadLittleEndianInt32(),
                        Flags = stream.ReadLittleEndianInt32(),
                        ReservedBytes = new byte[8]
                    };

                    stream.Read(hdr.ReservedBytes, 8);
                    if (IsValidTag(hdr))
                        return hdr;

                    startHeaderPosition -= ApeTag.HeaderSize;
                    stream.Position = startHeaderPosition + 1;
                    break;
                }
                startHeaderPosition++;
            }
            return null;
        }
예제 #4
0
        /// <summary>
        /// Reads the header.
        /// </summary>
        /// <param name="sb">The <see cref="StreamBuffer"/>.</param>
        /// <returns>
        /// true if the header is read and valid; otherwise, false.
        /// </returns>
        /// <exception cref="System.ArgumentNullException">Thrown if <paramref name="sb"/> is null.</exception>
        private bool ReadHeader(StreamBuffer sb)
        {
            if (sb == null)
                throw new ArgumentNullException("sb");

            long startPosition = sb.Position;

            // Sync code '11111111111110'
            _header = sb.ReadBigEndianInt32();
            if (((_header >> 18) & FrameSync) != FrameSync)
                return false;

            /*
                Blocking strategy:
                    •0 : fixed-block size stream; frame header encodes the frame number
                    •1 : variable-block size stream; frame header encodes the sample number
            */
            long num = ReadBigEndianUtf8Int64(sb, out _sampleFrameNumberBytes);
            switch (BlockingStrategy)
            {
                case FlacBlockingStrategy.FixedBlocksize:
                    Samples = num;
                    FrameNumber = num
                                  *
                                  (FlacStream.StreamInfoMetadataBlocks.Any()
                                       ? FlacStream.StreamInfoMetadataBlocks.First().MinimumBlockSize
                                       : 1);
                    break;

                case FlacBlockingStrategy.VariableBlocksize:
                    Samples = num;
                    FrameNumber = -1;
                break;
            }

            /*
                Block size in inter-channel samples:
                    •0000 : reserved
                    •0001 : 192 samples
                    •0010-0101 : 576 * (2 ^ (n - 2)) samples, i.e. 576/1152/2304/4608
                    •0110 : get 8 bit (block size - 1) from end of header
                    •0111 : get 16 bit (block size - 1) from end of header
                    •1000-1111 : 256 * (2 ^ (n - 8)) samples, i.e. 256/512/1024/2048/4096/8192/16384/3276
            */
            int blockSize = (_header >> 12) & 0xF;
            switch (blockSize)
            {
                case 0x01:
                    BlockSize = 192;
                    break;

                case 0x02:
                case 0x03:
                case 0x04:
                case 0x05:
                    BlockSize = 576 << (blockSize - 2);
                    break;

                case 0x06:
                    BlockSize = sb.ReadByte() + 1;
                    break;

                case 0x07:
                    BlockSize = sb.ReadBigEndianInt16() + 1;
                    break;

                default:
                    BlockSize = 256 << (blockSize - 8);
                    break;
            }

            /*
                Sample rate:
                    •0000 : get from STREAMINFO metadata block
                    •0001 : 88.2kHz
                    •0010 : 176.4kHz
                    •0011 : 192kHz
                    •0100 : 8kHz
                    •0101 : 16kHz
                    •0110 : 22.05kHz
                    •0111 : 24kHz
                    •1000 : 32kHz
                    •1001 : 44.1kHz
                    •1010 : 48kHz
                    •1011 : 96kHz
                    •1100 : get 8 bit sample rate (in kHz) from end of header
                    •1101 : get 16 bit sample rate (in Hz) from end of header
                    •1110 : get 16 bit sample rate (in tens of Hz) from end of header
                    •1111 : invalid, to prevent sync-fooling string of 1s
            */
            int samplingRate = (_header >> 8) & 0xF;
            if (samplingRate == 0x00)
            {
                SamplingRate = FlacStream.StreamInfoMetadataBlocks.Any()
                                   ? FlacStream.StreamInfoMetadataBlocks.First().SampleRate
                                   : 0;
            }
            else if (samplingRate <= 0x0B)
            {
                SamplingRate = SampleRates[samplingRate];
            }
            else
            {
                switch (samplingRate)
                {
                    case 0x0C:
                        // Sample rate in kHz
                        SamplingRate = sb.ReadByte() * 1000;
                        break;

                    case 0x0D:
                        // Sample rate in Hz
                        SamplingRate = sb.ReadBigEndianInt16();
                        break;

                    case 0x0E:
                        // Sample rate in 10s of Hz
                        SamplingRate = sb.ReadBigEndianInt16() * 10;
                        break;
                }
            }

            /*
                Channel assignment
                    •0000-0111 : (number of independent channels)-1. Where defined, the channel order follows SMPTE/ITU-R recommendations.
                    The assignments are as follows:
                        ◦1 channel: mono
                        ◦2 channels: left, right
                        ◦3 channels: left, right, center
                        ◦4 channels: front left, front right, back left, back right
                        ◦5 channels: front left, front right, front center, back/surround left, back/surround right
                        ◦6 channels: front left, front right, front center, LFE, back/surround left, back/surround right
                        ◦7 channels: front left, front right, front center, LFE, back center, side left, side right
                        ◦8 channels: front left, front right, front center, LFE, back left, back right, side left, side right
                    •1000 : left/side stereo: channel 0 is the left channel, channel 1 is the side(difference) channel
                    •1001 : right/side stereo: channel 0 is the side(difference) channel, channel 1 is the right channel
                    •1010 : mid/side stereo: channel 0 is the mid(average) channel, channel 1 is the side(difference) channel
                    •1011-1111 : reserved
            */
            int channelAssignment = (_header >> 4) & 0xF;
            if (channelAssignment < 0x08)
            {
                ChannelAssignment = FlacChannelAssignment.Independent;
                Channels = channelAssignment + 1;
            }
            else
            {
                Channels = 2;
                switch (channelAssignment)
                {
                    case 0x08:
                        ChannelAssignment = FlacChannelAssignment.LeftSide;
                        break;

                    case 0x09:
                        ChannelAssignment = FlacChannelAssignment.RightSide;
                        break;

                    case 0x0A:
                        ChannelAssignment = FlacChannelAssignment.MidSide;
                        break;
                }
            }

            /*
                Sample size in bits:
                    •000 : get from STREAMINFO metadata block
                    •001 : 8 bits per sample
                    •010 : 12 bits per sample
                    •011 : reserved
                    •100 : 16 bits per sample
                    •101 : 20 bits per sample
                    •110 : 24 bits per sample
                    •111 : reserved
            */
            int sampleSize = (_header >> 0x01) & 0x07;
            SampleSize = (sampleSize == 0x00)
                             ? (FlacStream.StreamInfoMetadataBlocks.Any()
                                    ? FlacStream.StreamInfoMetadataBlocks.First().BitsPerSample
                                    : 0)
                             : SampleSizes[sampleSize];

            _crc8 = sb.ReadByte();

            long endPosition = sb.Position;
            long length = endPosition - startPosition;
            byte[] crcBytes = new byte[length];
            sb.Position -= length;
            sb.Read(crcBytes, (int)length);
            byte crc8 = Crc8.Calculate(crcBytes);
            if (_crc8 != crc8)
                throw new InvalidDataException("Corrupt CRC8.");

            return true;
        }
예제 #5
0
        ////------------------------------------------------------------------------------------------------------------------------------
        private static long ReadBigEndianUtf8Int64(StreamBuffer sb, out byte[] utf8Bytes)
        {
            //// Decoded long range              Coded value
            //// 0000 0000 ・00 0000 007F   0xxxxxxx
            //// 0000 0080 ・00 0000 07FF   110xxxxx 10xxxxxx
            //// 0000 0800 ・00 0000 FFFF    1110xxxx 10xxxxxx 10xxxxxx
            //// 0001 0000 ・00 001F FFFF    11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
            //// 0020 0000 ・00 03FF FFFF     111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
            //// 0400 0000 ・00 7FFF FFFF     1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
            //// 8000 0000 ・0F FFFF FFFF     11111110 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
            // Where xxx represent the bits in the uncoded value, in the same order.
            const int ByteCountMask = 0x80;     // 10000000
            const int ByteMask = 0x3F;               // 00111111
            int byteCount = 1;
            long value = sb.ReadByte();
            if (value > ByteCountMask)
            {
                int bytes = 0;
                while (((value << bytes) & ByteCountMask) == ByteCountMask)
                    bytes++;

                value &= ByteMask >> (bytes - 1);
                for (int i = bytes - 1; i > 0; i--)
                    value = (value << (6 * i)) | ((long)sb.ReadByte() & ByteMask);

                byteCount += bytes - 1;
            }
            sb.Position -= byteCount;
            utf8Bytes = new byte[byteCount];
            sb.Read(utf8Bytes, byteCount);
            return value;
        }
예제 #6
0
        private static MusicMatchHeader ReadHeaderFooter(StreamBuffer stream, long startHeaderPosition, long endHeaderPosition, IList<byte> identifierBytes, TagOrigin tagOrigin)
        {
            if (stream == null)
                throw new ArgumentNullException("stream");

            stream.Position = startHeaderPosition;
            while (startHeaderPosition < endHeaderPosition)
            {
                int y = 0;
                while (stream.ReadByte() == identifierBytes[y++])
                {
                    startHeaderPosition++;
                    if (y != identifierBytes.Count)
                        continue;

                    if (tagOrigin == TagOrigin.Start)
                    {
                        MusicMatchHeader header = new MusicMatchHeader
                        {
                            Position = stream.Position - identifierBytes.Count,
                            Padding1 = new byte[2],
                            Padding2 = new byte[2],
                            Padding3 = new byte[2],
                            SpacePadding2 = new byte[226]
                        };

                        // 0x00 0x00 Padding
                        stream.Read(header.Padding1, header.Padding1.Length);

                        // <8-byte numerical ASCII string>
                        header.XingEncoderVersion = stream.ReadString(8);

                        // 0x00 0x00 Padding
                        stream.Read(header.Padding2, header.Padding2.Length);

                        // Xing encoder version <8-byte numerical ASCII string>
                        header.MusicMatchVersion = stream.ReadString(8);

                        // 0x00 0x00 Padding
                        stream.Read(header.Padding3, header.Padding3.Length);

                        // Space padding <226 * 0x20 >
                        stream.Read(header.SpacePadding2, header.SpacePadding2.Length);

                        ValidateHeader(header, null);
                        return header;
                    }

                    if (tagOrigin == TagOrigin.End)
                    {
                        MusicMatchHeader footer = new MusicMatchHeader
                        {
                            Position = stream.Position - identifierBytes.Count,
                            SpacePadding1 = new byte[13],
                            SpacePadding2 = new byte[12]
                        };

                        // Space padding <13 * 0x20>
                        stream.Read(footer.SpacePadding1, 13);

                        // version <4-byte numerical ASCII string> e.g. 3.05
                        footer.MusicMatchVersion = stream.ReadString(4);

                        // Space padding <12 * 0x20>
                        stream.Read(footer.SpacePadding2, 12);

                        ValidateHeader(null, footer);
                        return footer;
                    }
                }
                startHeaderPosition++;
            }
            return null;
        }
예제 #7
0
        /// <summary>
        /// Reads the extended header.
        /// </summary>
        /// <param name="streamBuffer">The stream buffer.</param>
        /// <param name="tag">The tag.</param>
        /// <param name="crcData">The CRC data.</param>
        /// <returns>
        /// The extended header if used; otherwise, null.
        /// </returns>
        /// <exception cref="System.IO.InvalidDataException">Thrown if the extended header size does not match the amount of bytes read for the extended header.</exception>
        private static Id3v2ExtendedHeader ReadExtendedHeader(StreamBuffer streamBuffer, Id3v2Tag tag, out int crcData)
        {
            crcData = 0;
            if (!tag.UseExtendedHeader)
                return null;

            // The extended header contains information that can provide further insight in the structure of the tag,
            // but is not vital to the correct parsing of the tag information; hence the extended header is optional.
            int extendedHeaderSize = 0;
            long startPosition = streamBuffer.Position;
            Id3v2ExtendedHeader extendedHeader = null;
            if ((tag.Version >= Id3v2Version.Id3v230) && (tag.Version < Id3v2Version.Id3v240))
            {
                // Where the 'Extended header size', currently 6 or 10 bytes, excludes itself.
                extendedHeaderSize = streamBuffer.ReadBigEndianInt32() + 4;
                int extendedFlags = streamBuffer.ReadBigEndianInt16();
                extendedHeader = Id3v2ExtendedHeader.InitExtendedHeader(tag.Version, extendedFlags);
                extendedHeader.PaddingSize = streamBuffer.ReadBigEndianInt32();
                if (extendedHeader.CrcDataPresent)
                    crcData = streamBuffer.ReadBigEndianInt32();
            }
            else if (tag.Version >= Id3v2Version.Id3v240)
            {
                // Where the 'Extended header size' is the size of the whole extended header, stored as a 32 bit synchsafe integer.
                // An extended header can thus never have a size of fewer than six bytes.
                extendedHeaderSize = streamBuffer.ReadBigEndianInt32();
                extendedHeaderSize = Id3v2Tag.GetUnsynchedValue(extendedHeaderSize);
                int extendedFlagsFieldLength = streamBuffer.ReadByte();

                // The extended flags field, with its size described by 'number of flag bytes', is defined as: %0bcd0000
                int extendedFlags = streamBuffer.ReadInt(extendedFlagsFieldLength);
                extendedHeader = Id3v2ExtendedHeader.InitExtendedHeader(tag.Version, extendedFlags);
                extendedHeader.SetExtendedFlagsFieldLength(extendedFlagsFieldLength);

                // Each flag that is set in the extended header has data attached,
                // which comes in the order in which the flags are encountered (i.e. the data for flag 'b' comes before the data for flag 'c').
                // Unset flags cannot have any attached data. All unknown flags MUST be unset and their corresponding data removed when a tag is modified.
                //
                // Every set flag's data starts with a length byte, which contains a value between 0 and 127 ($00 - $7f),
                // followed by data that has the field length indicated by the length byte.
                // If a flag has no attached data, the value $00 is used as length byte.

                // If this flag is set, the present tag is an update of a tag found earlier in the present file or stream.
                // If frames defined as unique are found in the present tag, they are to override any corresponding ones found in the earlier tag.
                // This flag has no corresponding data.
                if (extendedHeader.TagIsUpdate)
                {
                    // If a flag has no attached data, the value $00 is used as length byte.
                    streamBuffer.ReadByte();
                }

                // If this flag is set, a CRC-32 [ISO-3309] data is included in the extended header.
                // The CRC is calculated on all the data between the header and footer as indicated by the header's tag length field, minus the extended header.
                // Note that this includes the padding (if there is any), but excludes the footer.
                // The CRC-32 is stored as an 35 bit synchsafe integer, leaving the upper four bits always zeroed.
                if (extendedHeader.CrcDataPresent)
                {
                    long crcBytes = streamBuffer.ReadBigEndianInt64(5);
                    crcData = (int)Id3v2Tag.GetUnsynchedValue(crcBytes, 5);
                }

                // For some applications it might be desired to restrict a tag in more ways than imposed by the ID3v2 specification.
                // Note that the presence of these restrictions does not affect how the tag is decoded, merely how it was restricted before encoding.
                // If this flag is set the tag is restricted as follows:
                if (extendedHeader.TagIsRestricted)
                {
                    // Restrictions: %ppqrrstt
                    byte tagRestrictions = (byte)streamBuffer.ReadByte();
                    extendedHeader.TagRestrictions = new Id3v2TagRestrictions
                    {
                        // p - Tag size restrictions
                        TagSizeRestriction = (Id3v2TagSizeRestriction)(tagRestrictions & Id3v2TagRestrictions.TagSizeRestrictionFlags),

                        // q - Text encoding restrictions
                        TextEncodingRestriction = (Id3v2TextEncodingRestriction)(tagRestrictions & Id3v2TagRestrictions.TextEncodingRestrictionFlags),

                        // r - Text fields size restrictions
                        TextFieldsSizeRestriction = (Id3v2TextFieldsSizeRestriction)(tagRestrictions & Id3v2TagRestrictions.TextFieldsSizeRestrictionFlags),

                        // s - Image encoding restrictions
                        ImageEncodingRestriction = (Id3v2ImageEncodingRestriction)(tagRestrictions & Id3v2TagRestrictions.ImageEncodingRestrictionFlags),

                        // t - Image size restrictions
                        ImageSizeRestriction = (Id3v2ImageSizeRestriction)(tagRestrictions & Id3v2TagRestrictions.ImageSizeRestrictionFlags)
                    };
                }
            }

            if ((streamBuffer.Position - startPosition) != extendedHeaderSize)
            {
                throw new InvalidDataException(
                    string.Format(
                        "ExtendedHeaderSize does not match amount of bytes read: expected {0} but got {1} bytes.",
                        extendedHeaderSize,
                        streamBuffer.Position - startPosition));
            }
            return extendedHeader;
        }
예제 #8
0
        private static Id3v2Header ReadHeader(StreamBuffer stream, long startHeaderPosition, long endHeaderPosition, byte[] identifierBytes)
        {
            if (stream == null)
                throw new ArgumentNullException("stream");

            stream.Position = startHeaderPosition;

            // Look for a header/footer between the start position and end position.
            while (startHeaderPosition < endHeaderPosition)
            {
                int y = 0;

                // identifierBytes is the HeaderIdentifier or the FooterIdentifier encoded.
                while (stream.ReadByte() == identifierBytes[y++])
                {
                    startHeaderPosition++;
                    if (y != identifierBytes.Length)
                        continue;

                    // The first byte of ID3 version is it's major version, while the second byte is its revision number.
                    // All revisions are backwards compatible while major versions are not.
                    // If software with ID3v2 and below support should encounter version three or higher it should simply ignore the whole tag.
                    // Version and revision will never be $FF.
                    int majorRevision = stream.ReadByte();
                    int revisionNumber = stream.ReadByte();
                    if ((majorRevision >= 0x10) || (revisionNumber >= 0x10))
                    {
                        stream.Position -= 2;
                        break;
                    }

                    // Return header/footer found.
                    return new Id3v2Header
                               {
                                   Position = stream.Position - identifierBytes.Length - 2,
                                   Identifier = Encoding.ASCII.GetString(identifierBytes),
                                   Version = (Id3v2Version)((majorRevision * 10) + revisionNumber),

                                   // One byte of flags.
                                   // ID3v2.2.0: %xx000000
                                   Flags = (byte)stream.ReadByte(),

                                   // The ID3 tag size is encoded with four bytes where the first bit (bit 7) is set to zero in every byte, making a total of 28 bits.
                                   // The zeroed bits are ignored, so a 257 bytes long tag is represented as $00 00 02 01.
                                   // ID3v2.2.0: The ID3 tag size is the size of the complete tag after unsychronisation, including padding, excluding the header (total tag size - 10).
                                   Size = Id3v2Tag.GetUnsynchedValue(stream.ReadBigEndianInt32())
                               };
                }
                startHeaderPosition++;
            }
            return null;
        }
예제 #9
0
        ////------------------------------------------------------------------------------------------------------------------------------
        private static ApeItem ReadItem(ApeVersion version, StreamBuffer sb, long maximumItemSize)
        {
            if (sb == null)
                throw new ArgumentNullException("sb");

            // Find the item.
            long startPosition = sb.Position;
            long bytesToSkip = GetBytesUntilNextItem(version, sb, maximumItemSize);

            // Not found; return null.
            if (bytesToSkip == -1)
                return null;

            // Move the stream position to the start of the frame.
            sb.Position = startPosition + bytesToSkip;

            int valueSize = sb.ReadLittleEndianInt32();
            if ((valueSize <= 0) || (valueSize > ApeTag.MaxAllowedSize))
                return null;

            int flags = sb.ReadLittleEndianInt32();
            maximumItemSize -= 8;

            int itemKeyLengthBytes = 0;
            long maximumBytesToRead = maximumItemSize;
            if (maximumBytesToRead > 0)
            {
                for (int y = 0; y < maximumBytesToRead; y++)
                {
                    int character = sb.ReadByte();
                    if (character == 0x00) // 0x00 byte - string terminator.
                        break;

                    itemKeyLengthBytes++;
                }
            }

            // Name
            sb.Seek(-(itemKeyLengthBytes + 1), SeekOrigin.Current);
            string key = sb.ReadString(itemKeyLengthBytes, Encoding.UTF8);
            if ((key.Length < MinKeyLengthCharacters) || (itemKeyLengthBytes > MaxKeyLengthBytes))
                return null;

            // Skip Item key terminator (0x00 byte)
            int keyTerminator = sb.ReadByte();
            if (keyTerminator != 0x00)
                return null;

            ApeItem item = GetItem(version, key, flags);
            return item.ReadItem(version, valueSize, sb, maximumItemSize) ? item : null;
        }
예제 #10
0
        ////------------------------------------------------------------------------------------------------------------------------------
        private static FlacMetadataBlock ReadBlock(StreamBuffer stream)
        {
            int flags = stream.ReadByte();

            // Length
            int length = stream.ReadBigEndianInt(3);
            if (length >= stream.Length)
                return null;

            byte[] data = new byte[length];
            stream.Read(data, length);

            FlacMetadataBlock metadataBlock;
            FlacMetadataBlockType blockType = (FlacMetadataBlockType)(flags & HeaderFlags.BlockType);
            switch (blockType)
            {
                case FlacMetadataBlockType.Padding:
                    metadataBlock = new FlacPaddingMetadataBlock();
                    break;

                case FlacMetadataBlockType.Application:
                    metadataBlock = new FlacApplicationMetadataBlock();
                    break;

                case FlacMetadataBlockType.StreamInfo:
                    metadataBlock = new FlacStreamInfoMetadataBlock();
                    break;

                case FlacMetadataBlockType.SeekTable:
                    metadataBlock = new FlacSeekTableMetadataBlock();
                    break;

                case FlacMetadataBlockType.VorbisComment:
                    metadataBlock = new FlacVorbisCommentsMetadataBlock();
                    break;

                case FlacMetadataBlockType.CueSheet:
                    metadataBlock = new FlacCueSheetMetadataBlock();
                    break;

                case FlacMetadataBlockType.Picture:
                    metadataBlock = new FlacPictureMetadataBlock();
                    break;

                default:
                    metadataBlock = new FlacMetadataBlock();
                    break;
            }
            metadataBlock.Flags = flags;
            metadataBlock.Data = data;
            return metadataBlock;
        }
예제 #11
0
            /// <summary>
            /// Reads the <see cref="Id3v2FrameEncodingType"/> from the stream.
            /// </summary>
            /// <param name="streamBuffer">The stream buffer.</param>
            /// <returns>
            /// The <see cref="Id3v2FrameEncodingType"/>.
            /// </returns>
            /// <remarks>
            /// Since the encoding type is first read from the stream, the position should be set to the byte containing the encoding type.
            /// If the encoding type is <see cref="Id3v2FrameEncodingType.UTF16LittleEndian"/>, 
            /// it will try to read the byte order marker from the stream 
            /// to see if the encoding type is <see cref="Id3v2FrameEncodingType.UTF16BigEndian"/>.
            /// If no byte order marker is found or if the byte order marker is not recognized, 
            /// it will return <see cref="Id3v2FrameEncodingType.UTF16LittleEndian"/> as default encoding.
            /// <para />
            /// The position of the stream will not be modified.
            /// </remarks>
            public static Id3v2FrameEncodingType ReadEncodingTypeFromStream(StreamBuffer streamBuffer)
            {
                int encodingByte = streamBuffer.ReadByte();
                if ((encodingByte == -1) || !IsValidEncodingType(encodingByte))
                    return Id3v2FrameEncodingType.Default;

                if (encodingByte > (byte)Id3v2FrameEncodingType.UTF16LittleEndian)
                    encodingByte += 1;

                // Cast the encoding type.
                Id3v2FrameEncodingType encodingType = (Id3v2FrameEncodingType)encodingByte;

                // If it's not little endian, then we don't need to figure out if it's little or big; return here.
                if (encodingType != Id3v2FrameEncodingType.UTF16LittleEndian)
                    return encodingType;

                // See which byte order the frame encoding is.
                byte[] byteOrderMarker = new byte[2];

                // Not enough bytes available; probably little endian then.
                if (streamBuffer.Read(byteOrderMarker, 2, false) < 2)
                    return Id3v2FrameEncodingType.UTF16LittleEndian;

                // Little endian byte order marker?
                if (((byteOrderMarker[0] == 0xFF) && (byteOrderMarker[1] == 0xFE))
                    || ((byteOrderMarker[0] == 0x00) && (byteOrderMarker[1] == 0x00)))
                    return Id3v2FrameEncodingType.UTF16LittleEndian;

                // Big endian byte order marker?
                if ((byteOrderMarker[0] == 0xFE) && (byteOrderMarker[1] == 0xFF))
                    return Id3v2FrameEncodingType.UTF16BigEndian;

                // Default to little endian.
                return Id3v2FrameEncodingType.UTF16LittleEndian;
            }
예제 #12
0
 public void ReadByteTestMovePositionFalse()
 {
     const byte Value = 0xEF;
     const byte Expected = 0xEF;
     StreamBuffer target = new StreamBuffer(BitConverter.GetBytes(Value)) { Position = 0 };
     int actual = target.ReadByte(false);
     Assert.AreEqual(Expected, actual);
     Assert.IsTrue(target.Position == 0);
 }
예제 #13
0
        ////------------------------------------------------------------------------------------------------------------------------------
        /// <summary>
        /// Initializes a new instance of the <see cref="LameTag"/> class.
        /// </summary>
        /// <param name="firstFrameBuffer">The first frame buffer containing a <see cref="LameTag"/>.</param>
        public LameTag(StreamBuffer firstFrameBuffer)
        {
            // string lameTag = "LAME"
            firstFrameBuffer.ReadString(4);
            float ver;
            float.TryParse(firstFrameBuffer.ReadString(4), out ver);
            Version = ver;

            firstFrameBuffer.Seek(-8, SeekOrigin.Current);
            if (Version < 3.90f)
            {
                // Initial LAME info, 20 bytes for LAME tag. for example, "LAME3.12 (beta 6)"
                // LAME prior to 3.90 writes only a 20 byte encoder string.
                EncoderVersion = firstFrameBuffer.ReadString(20);
            }
            else
            {
                EncoderVersion = firstFrameBuffer.ReadString(9);

                // Revision Information Tag + VBR Info
                int infoAndVbr = firstFrameBuffer.ReadByte();

                // Revision information in 4 MSB
                InfoTagRevision = infoAndVbr >> 4;
                if (InfoTagRevision == Formats.InfoTagRevision.Reserved)
                    throw new ArgumentException("InfoTagRevision bit is set to reserved (0xF)");

                // VBR info in 4 LSB
                VbrMethod = infoAndVbr & 0x0F;

                // lowpass information, multiply by 100 to get hz
                LowpassFilterValue = firstFrameBuffer.ReadByte() * 100;

                // Radio replay gain fields
                // Peak signal amplitude
                PeakSignalAmplitude = firstFrameBuffer.ReadFloat();

                // Radio Replay Gain
                RadioReplayGain = firstFrameBuffer.ReadInt16();

                // Audiophile Replay Gain
                AudiophileReplayGain = firstFrameBuffer.ReadInt16();

                // Encoding Flags + ATH type
                int encodingFlagsAndAthType = firstFrameBuffer.ReadByte();

                // Encoding Flags in 4 MSB
                EncodingFlags = encodingFlagsAndAthType >> 4;

                // LAME ATH Type in 4 LSB
                AthType = encodingFlagsAndAthType & 0x0F;

                // If ABR, this will be the specified bitrate
                // Otherwise (CBR/VBR), the minimal bitrate (255 means 255 or bigger)
                BitRate = firstFrameBuffer.ReadByte();

                // the 12 bit values (0-4095) of how many samples were added at start (encoder delay)
                // in X and how many 0-samples were padded at the end in Y to complete the last frame.
                EncoderDelays = firstFrameBuffer.ReadInt(3);
                EncoderDelaySamples = EncoderDelays & 0xFFF;
                EncoderDelayPaddingSamples = EncoderDelays >> 12;
                ////int numberSamplesInOriginalWav = frameCount

                Misc = firstFrameBuffer.ReadByte();

                // Any mp3 can be amplified by a factor 2 ^ ( x * 0.25) in a lossless manner by a tool like eg. mp3gain
                // if done so, this 8-bit field can be used to log such transformation happened so that any given time it can be undone.
                Mp3Gain = firstFrameBuffer.ReadByte();

                // Preset and surround info
                PresetSurroundInfo = firstFrameBuffer.ReadInt16();

                // 32 bit integer filed containing the exact length in bytes of the mp3 file originally made by LAME excluded ID3 tag info at the end.
                MusicLength = firstFrameBuffer.ReadBigEndianInt32();

                // Contains a CRC-16 of the complete mp3 music data as made originally by LAME.
                _musicCrc = (short)firstFrameBuffer.ReadBigEndianInt16();

                // contains a CRC-16 of the first 190 bytes (0x00 - 0xBD) of the Info header frame.
                // This field is calculated at the end, once all other fields are completed.
                _infoTagCrc = (short)firstFrameBuffer.ReadBigEndianInt16();
            }
        }