unsafe void decode_metadata() { byte x; int i, id; bool first = true; byte[] FLAC__STREAM_SYNC_STRING = new byte[] { (byte)'f', (byte)'L', (byte)'a', (byte)'C' }; byte[] ID3V2_TAG_ = new byte[] { (byte)'I', (byte)'D', (byte)'3' }; for (i = id = 0; i < 4; ) { if (_IO.Read(_framesBuffer, 0, 1) == 0) throw new Exception("FLAC stream not found"); x = _framesBuffer[0]; if (x == FLAC__STREAM_SYNC_STRING[i]) { first = true; i++; id = 0; continue; } if (id < 3 && x == ID3V2_TAG_[id]) { id++; i = 0; if (id == 3) { if (!skip_bytes(3)) throw new Exception("FLAC stream not found"); int skip = 0; for (int j = 0; j < 4; j++) { if (0 == _IO.Read(_framesBuffer, 0, 1)) throw new Exception("FLAC stream not found"); skip <<= 7; skip |= ((int)_framesBuffer[0] & 0x7f); } if (!skip_bytes(skip)) throw new Exception("FLAC stream not found"); } continue; } id = 0; if (x == 0xff) /* MAGIC NUMBER for the first 8 frame sync bits */ { do { if (_IO.Read(_framesBuffer, 0, 1) == 0) throw new Exception("FLAC stream not found"); x = _framesBuffer[0]; } while (x == 0xff); if (x >> 2 == 0x3e) /* MAGIC NUMBER for the last 6 sync bits */ { //_IO.Position -= 2; // state = frame throw new Exception("headerless file unsupported"); } } throw new Exception("FLAC stream not found"); } do { fill_frames_buffer(); fixed (byte* buf = _framesBuffer) { BitReader bitreader = new BitReader(buf, _framesBufferOffset, _framesBufferLength - _framesBufferOffset); bool is_last = bitreader.readbit() != 0; MetadataType type = (MetadataType)bitreader.readbits(7); int len = (int)bitreader.readbits(24); if (type == MetadataType.StreamInfo) { const int FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN = 16; /* bits */ const int FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN = 16; /* bits */ const int FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN = 24; /* bits */ const int FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN = 24; /* bits */ const int FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN = 20; /* bits */ const int FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN = 3; /* bits */ const int FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN = 5; /* bits */ const int FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN = 36; /* bits */ const int FLAC__STREAM_METADATA_STREAMINFO_MD5SUM_LEN = 128; /* bits */ min_block_size = bitreader.readbits(FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN); max_block_size = bitreader.readbits(FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN); min_frame_size = bitreader.readbits(FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN); max_frame_size = bitreader.readbits(FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN); int sample_rate = (int)bitreader.readbits(FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN); int channels = 1 + (int)bitreader.readbits(FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN); int bits_per_sample = 1 + (int)bitreader.readbits(FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN); pcm = new AudioPCMConfig(bits_per_sample, channels, sample_rate); _sampleCount = (long)bitreader.readbits64(FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN); bitreader.skipbits(FLAC__STREAM_METADATA_STREAMINFO_MD5SUM_LEN); } else if (type == MetadataType.Seektable) { int num_entries = len / 18; seek_table = new SeekPoint[num_entries]; for (int e = 0; e < num_entries; e++) { seek_table[e].number = (long)bitreader.readbits64(Flake.FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN); seek_table[e].offset = (long)bitreader.readbits64(Flake.FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN); seek_table[e].framesize = (int)bitreader.readbits24(Flake.FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN); } } if (_framesBufferLength < 4 + len) { _IO.Position += 4 + len - _framesBufferLength; _framesBufferLength = 0; } else { _framesBufferLength -= 4 + len; _framesBufferOffset += 4 + len; } if (is_last) break; } } while (true); first_frame_offset = _IO.Position - _framesBufferLength; }