예제 #1
0
        /// <summary>
        /// Finds the <see cref="VbriHeader"/> header within the <paramref name="firstFrame"/>.
        /// </summary>
        /// <param name="firstFrame">The first frame.</param>
        /// <returns>The VBRI header if found; otherwise, null.</returns>
        /// <remarks>
        /// The VBRI header is located exactly 32 bytes after the end of the first MPEG audio header in the file.
        /// It will compare the first 4 bytes against the <see cref="HeaderIndicator"/> 
        /// to see if the header contains a <see cref="VbriHeader"/> or not.
        /// </remarks>
        public static new VbriHeader FindHeader(MpaFrame firstFrame)
        {
            if (firstFrame == null)
                throw new ArgumentNullException("firstFrame");

            using (StreamBuffer buffer = new StreamBuffer())
            {
                byte[] data = firstFrame.ToByteArray();
                buffer.Write(data);

                // 32 bytes = data indicating silence
                const long Offset = MpaFrame.FrameHeaderSize + SilenceDataSize;
                buffer.Seek(Offset, SeekOrigin.Begin);
                string tagName = buffer.ReadString(4, false, false);
                return String.Compare(tagName, HeaderIndicator, StringComparison.OrdinalIgnoreCase) == 0
                           ? new VbriHeader(firstFrame, buffer, Offset)
                           : null;
            }
        }
예제 #2
0
        /// <summary>
        /// Finds the <see cref="VbriHeader"/> header within the <paramref name="firstFrame"/>.
        /// </summary>
        /// <param name="firstFrame">The first frame.</param>
        /// <returns>The VBRI header if found; otherwise, null.</returns>
        /// <remarks>
        /// The XING header is located after the side information in Layer III in the first MPEG audio header in the file.
        /// It will compare the first 4 bytes against the <see cref="VbrHeaderIndicator"/> 
        /// to see if the header contains a <see cref="XingHeader"/> or not.
        /// </remarks>
        public static new XingHeader FindHeader(MpaFrame firstFrame)
        {
            if (firstFrame == null)
                throw new ArgumentNullException("firstFrame");

            long offset = MpaFrame.FrameHeaderSize + firstFrame.SideInfoSize;
            using (StreamBuffer buffer = new StreamBuffer())
            {
                byte[] data = firstFrame.ToByteArray();
                buffer.Write(data);

                buffer.Seek(offset, SeekOrigin.Begin);
                string tagName = buffer.ReadString(4, false, false);
                if ((String.Compare(tagName, VbrHeaderIndicator, StringComparison.OrdinalIgnoreCase) == 0)
                    || (String.Compare(tagName, CbrHeaderIndicator, StringComparison.OrdinalIgnoreCase) == 0))
                    return new XingHeader(firstFrame, buffer, offset);
            }
            return null;
        }
예제 #3
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;
        }
예제 #4
0
 public void SeekTest()
 {
     StreamBuffer target = new StreamBuffer();
     target.WritePadding(0x00, 1024);
     const long Offset = 100;
     const SeekOrigin Loc = new SeekOrigin();
     const long Expected = 100;
     long actual= target.Seek(Offset, Loc);
     Assert.AreEqual(Expected, actual);
 }
예제 #5
0
        ////------------------------------------------------------------------------------------------------------------------------------
        /// <summary>
        /// Finds a <see cref="LameTag"/> in the given stream.
        /// </summary>
        /// <param name="firstFrameBuffer">The first frame buffer.</param>
        /// <param name="offset">The offset.</param>
        /// <returns>The <see cref="LameTag"/> when found; otherwise, null.</returns>
        public static LameTag FindTag(StreamBuffer firstFrameBuffer, long offset)
        {
            if (firstFrameBuffer == null)
                throw new ArgumentNullException("firstFrameBuffer");

            // If limiting the LAME string to 9 bytes "LAME X.YZu", the extension revision 0 could take 27 bytes and it would still fit a 64 kbit 48kHz frame.
            firstFrameBuffer.Seek(offset, SeekOrigin.Begin);
            string tagName = firstFrameBuffer.ReadString(4, false, false);
            return String.Compare(tagName, "LAME", StringComparison.OrdinalIgnoreCase) == 0 ? new LameTag(firstFrameBuffer) : null;
        }
예제 #6
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();
            }
        }