bool ReadV2Frame( PrimitiveReader reader, ref int len )
        {
            string frameId = reader.ReadASCIIString( 4 ); len -= 4;
            if( frameId == "\0\0\0\0" ) return true;

            int frameDataSize = reader.ReadUInt24(); len -= ( frameDataSize + 3 );
            Console.WriteLine( "reading frame: " + frameId );
            Console.WriteLine( "   skipping frame." );
            reader.SkipData( frameDataSize );
            return false;
        }
        bool ReadMetadataBlock( PrimitiveReader reader )
        {
            byte flags = reader.ReadByte();
            bool lastBlock = ( flags & 0x80 ) != 0;
            flags &= 0x7F;
            MetadataBlockType blockType = (MetadataBlockType)flags;
            int metaLength = reader.ReadUInt24();

            switch( blockType ) {
                case MetadataBlockType.StreamInfo:
                    ProcessMetadataStreamInfo( metaLength, reader );
                    break;

                case MetadataBlockType.Padding:
                    ProcessMetadataPadding( metaLength, reader );
                    break;

                case MetadataBlockType.Application:
                    ProcessMetadataApplication( metaLength, reader );
                    break;

                case MetadataBlockType.SeekTable:
                    ProcessMetadataSeekTable( metaLength, reader );
                    break;

                case MetadataBlockType.VorbisComment:
                    ProcessMetadataVorbisComment( metaLength, reader );
                    break;

                case MetadataBlockType.Cuesheet:
                    ProcessMetadataCuesheet( metaLength, reader );
                    break;

                case MetadataBlockType.Picture:
                    ProcessMetadataPicture( metaLength, reader );
                    break;

                default:
                    throw new InvalidDataException( "Invalid metadata block type." );
            }
            return lastBlock;
        }
        void ProcessMetadataStreamInfo( int len, PrimitiveReader reader )
        {
            short minBlockSize = reader.ReadInt16();
            short maxBlockSize = reader.ReadInt16();
            int minFrameSize = reader.ReadUInt24();
            int maxFrameSize = reader.ReadUInt24();

            FlacBitReader bitReader = new FlacBitReader( reader );
            bitReader.BigEndian = true;
            int sampleRate = bitReader.ReadBits( 20 );
            Metadata[MetadataKeys.SampleRate] = sampleRate.ToString();
            int channels = bitReader.ReadBits( 3 ) + 1;
            Metadata[MetadataKeys.Channels] = channels.ToString();
            int bitsPerSample = bitReader.ReadBits( 5 ) + 1;
            Metadata[MetadataKeys.BitsPerSample] = bitsPerSample.ToString();
            long totalSamples = bitReader.ReadBits64( 36 );
            Metadata["Total samples"] = totalSamples.ToString();

            channelCount = channels;
            metaSampleRate = sampleRate;
            metaBitsPerSample = bitsPerSample;
            byte[] md5hash = reader.ReadBytes( 16 );
        }