VBRInfo ParseVBRI() { VBRInfo info = new VBRInfo(); info.Channels = Channels; info.SampleRate = SampleRate; info.SampleCount = SampleCount; // VBRI is "fixed" size... Yay. :) var buf = new byte[26]; if (Read(36, buf) != 26) { return(null); } // Version var version = buf[4] << 8 | buf[5]; // Delay info.VBRDelay = buf[6] << 8 | buf[7]; // Quality info.VBRQuality = buf[8] << 8 | buf[9]; // Bytes info.VBRBytes = buf[10] << 24 | buf[11] << 16 | buf[12] << 8 | buf[13]; // Frames info.VBRFrames = buf[14] << 24 | buf[15] << 16 | buf[16] << 8 | buf[17]; // TOC // entries var tocEntries = buf[18] << 8 | buf[19]; var tocScale = buf[20] << 8 | buf[21]; var tocEntrySize = buf[22] << 8 | buf[23]; var tocFramesPerEntry = buf[24] << 8 | buf[25]; var tocSize = tocEntries * tocEntrySize; var toc = new byte[tocSize]; if (Read(62, toc) != tocSize) { return(null); } return(info); }
public bool ParseVBR(out VBRInfo info) { Span <byte> buf = stackalloc byte[4]; // Xing first int offset; if (Version == MpegVersion.Version1 && ChannelMode != MpegChannelMode.Mono) { offset = 32 + 4; } else if (Version > MpegVersion.Version1 && ChannelMode == MpegChannelMode.Mono) { offset = 9 + 4; } else { offset = 17 + 4; } if (Read(offset, buf) == 4) { if (buf[0] == 'X' && buf[1] == 'i' && buf[2] == 'n' && buf[3] == 'g' || buf[0] == 'I' && buf[1] == 'n' && buf[2] == 'f' && buf[3] == 'o') { return(ParseXing(offset + 4, out info)); } // then VBRI (kinda rare) if (Read(36, buf) == 4) { if (buf[0] == 'V' && buf[1] == 'B' && buf[2] == 'R' && buf[3] == 'I') { return(ParseVBRI(out info)); } } } info = default; return(false); }
private bool ParseVBRI(out VBRInfo info) { info = new VBRInfo(); info.Channels = Channels; info.SampleRate = SampleRate; info.SampleCount = SampleCount; // VBRI is "fixed" size... Yay. :) Span <byte> buf = stackalloc byte[26]; if (Read(36, buf) != 26) { return(false); } int version = BinaryPrimitives.ReadInt16BigEndian(buf.Slice(4)); info.VBRDelay = BinaryPrimitives.ReadInt16BigEndian(buf.Slice(6)); info.VBRQuality = BinaryPrimitives.ReadInt16BigEndian(buf.Slice(8)); info.VBRBytes = BinaryPrimitives.ReadInt32BigEndian(buf.Slice(10)); info.VBRFrames = BinaryPrimitives.ReadInt32BigEndian(buf.Slice(14)); // TOC // entries int tocEntries = BinaryPrimitives.ReadInt16BigEndian(buf.Slice(18)); int tocScale = BinaryPrimitives.ReadInt16BigEndian(buf.Slice(20)); int tocEntrySize = BinaryPrimitives.ReadInt16BigEndian(buf.Slice(22)); int tocFramesPerEntry = BinaryPrimitives.ReadInt16BigEndian(buf.Slice(24)); int tocSize = tocEntries * tocEntrySize; var toc = new byte[tocSize]; if (Read(62, toc) != tocSize) { return(false); } return(true); }
VBRInfo ParseXing(int offset) { VBRInfo info = new VBRInfo(); info.Channels = Channels; info.SampleRate = SampleRate; info.SampleCount = SampleCount; var buf = new byte[100]; if (Read(offset, buf, 0, 4) != 4) { return(null); } offset += 4; var flags = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3]; // frame count if ((flags & 0x1) != 0) { if (Read(offset, buf, 0, 4) != 4) { return(null); } offset += 4; info.VBRFrames = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3]; } // byte count if ((flags & 0x2) != 0) { if (Read(offset, buf, 0, 4) != 4) { return(null); } offset += 4; info.VBRBytes = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3]; } // TOC if ((flags & 0x4) != 0) { // we're not using the TOC, so just discard it if (Read(offset, buf) != 100) { return(null); } offset += 100; } // scale if ((flags & 0x8) != 0) { if (Read(offset, buf, 0, 4) != 4) { return(null); } offset += 4; info.VBRQuality = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3]; } //// now look for a LAME header (note: if it isn't found, it doesn't fail the VBR parse) //do //{ // if (Read(offset, buf, 0, 20) != 20) break; // offset += 20; // // LAME tag revision: only 0 and 1 are valid // if ((buf[9] & 0xF0) > 0x10) break; // // VBR mode: 0-6, 8 & 9 are valid // var mode = buf[9] & 0xF; // if (mode == 7 || mode > 9) break; // // Lowpass filter value // var lowpass = buf[10] / 100.0; // // Replay Gain // var rgPeak = BitConverter.ToSingle(buf, 11); // var rgGainRadio = buf[15] << 8 | buf[16]; // var rgGain = buf[17] << 8 | buf[18]; //} while (false); return(info); }
FrameBase FindNextFrame() { // if we've found the end, don't bother looking for anything else if (_endFound) { return(null); } var freeFrame = _lastFree; var lastFrameStart = _readOffset; lock (_frameLock) { // read 3 bytes var syncBuf = new byte[4]; try { if (Read(_readOffset, syncBuf, 0, 4) == 4) { // now loop until a frame is found do { var sync = (uint)(syncBuf[0] << 24 | syncBuf[1] << 16 | syncBuf[2] << 8 | syncBuf[3]); lastFrameStart = _readOffset; // try ID3 first (for v2 frames) if (_id3Frame == null) { var f = ID3Frame.TrySync(sync); if (f != null) { if (f.Validate(_readOffset, this)) { if (!_canSeek) { f.SaveBuffer(); } _readOffset += f.Length; DiscardThrough(_readOffset, true); return(_id3Frame = f); } } } // now look for a RIFF header if (_first == null && _riffHeaderFrame == null) { var f = RiffHeaderFrame.TrySync(sync); if (f != null) { if (f.Validate(_readOffset, this)) { _readOffset += f.Length; DiscardThrough(_readOffset, true); return(_riffHeaderFrame = f); } } } // finally, just try for an MPEG frame var frame = MpegFrame.TrySync(sync); if (frame != null) { if (frame.Validate(_readOffset, this) && !(freeFrame != null && (frame.Layer != freeFrame.Layer || frame.Version != freeFrame.Version || frame.SampleRate != freeFrame.SampleRate || frame.BitRateIndex > 0 ) ) ) { if (!_canSeek) { frame.SaveBuffer(); DiscardThrough(_readOffset + frame.FrameLength, true); } _readOffset += frame.FrameLength; if (_first == null) { if (_vbrInfo == null && (_vbrInfo = frame.ParseVBR()) != null) { return(FindNextFrame()); } else { frame.Number = 0; _first = _last = frame; } } else { if (frame.SampleCount != _first.SampleCount) { _mixedFrameSize = true; } frame.SampleOffset = _last.SampleCount + _last.SampleOffset; frame.Number = _last.Number + 1; _last = (_last.Next = frame); } if (frame.BitRateIndex == 0) { _lastFree = frame; } return(frame); } } // if we've read MPEG frames and can't figure out what frame type we have, try looking for a new ID3 tag if (_last != null) { var f = ID3Frame.TrySync(sync); if (f != null) { if (f.Validate(_readOffset, this)) { if (!_canSeek) { f.SaveBuffer(); } // if it's a v1 tag, go ahead and parse it if (f.Version == 1) { _id3v1Frame = f; } else { // grrr... the ID3 2.4 spec says tags can be anywhere in the file and that later tags can override earlier ones... boo _id3Frame.Merge(f); } _readOffset += f.Length; DiscardThrough(_readOffset, true); return(f); } } } // well, we didn't find anything, so rinse and repeat with the next byte ++_readOffset; if (_first == null || !_canSeek) { DiscardThrough(_readOffset, true); } Buffer.BlockCopy(syncBuf, 1, syncBuf, 0, 3); } while (Read(_readOffset + 3, syncBuf, 3, 1) == 1); } // move the "end of frame" marker for the last free format frame (in case we have one) // this is because we don't include the last four bytes otherwise lastFrameStart += 4; _endFound = true; return(null); } finally { if (freeFrame != null) { freeFrame.Length = (int)(lastFrameStart - freeFrame.Offset); if (!_canSeek) { // gotta finish filling the buffer!! throw new InvalidOperationException("Free frames cannot be read properly from forward-only streams!"); } // if _lastFree hasn't changed (we got a non-MPEG frame), clear it out if (_lastFree == freeFrame) { _lastFree = null; } } } } }
private bool ParseXing(int offset, out VBRInfo info) { info = new VBRInfo(); info.Channels = Channels; info.SampleRate = SampleRate; info.SampleCount = SampleCount; Span <byte> buf = stackalloc byte[100]; if (Read(offset, buf.Slice(0, 4)) != 4) { return(false); } offset += 4; int flags = BinaryPrimitives.ReadInt32BigEndian(buf); // frame count if ((flags & 0x1) != 0) { if (Read(offset, buf.Slice(0, 4)) != 4) { return(false); } offset += 4; info.VBRFrames = BinaryPrimitives.ReadInt32BigEndian(buf); } // byte count if ((flags & 0x2) != 0) { if (Read(offset, buf.Slice(0, 4)) != 4) { return(false); } offset += 4; info.VBRBytes = BinaryPrimitives.ReadInt32BigEndian(buf); } // TOC if ((flags & 0x4) != 0) { // we're not using the TOC, so just discard it if (Read(offset, buf) != 100) { return(false); } offset += 100; } // scale if ((flags & 0x8) != 0) { if (Read(offset, buf.Slice(0, 4)) != 4) { return(false); } offset += 4; info.VBRQuality = BinaryPrimitives.ReadInt32BigEndian(buf); } //// now look for a LAME header (note: if it isn't found, it doesn't fail the VBR parse) //do //{ // if (Read(offset, buf, 0, 20) != 20) break; // offset += 20; // // LAME tag revision: only 0 and 1 are valid // if ((buf[9] & 0xF0) > 0x10) break; // // VBR mode: 0-6, 8 & 9 are valid // var mode = buf[9] & 0xF; // if (mode == 7 || mode > 9) break; // // Lowpass filter value // var lowpass = buf[10] / 100.0; // // Replay Gain // var rgPeak = BitConverter.ToSingle(buf, 11); // var rgGainRadio = buf[15] << 8 | buf[16]; // var rgGain = buf[17] << 8 | buf[18]; //} //while (false); return(true); }
VBRInfo ParseVBRI() { VBRInfo info = new VBRInfo(); info.Channels = Channels; info.SampleRate = SampleRate; info.SampleCount = SampleCount; // VBRI is "fixed" size... Yay. :) var buf = new byte[26]; if (Read(36, buf) != 26) return null; // Version var version = buf[4] << 8 | buf[5]; // Delay info.VBRDelay = buf[6] << 8 | buf[7]; // Quality info.VBRQuality = buf[8] << 8 | buf[9]; // Bytes info.VBRBytes = buf[10] << 24 | buf[11] << 16 | buf[12] << 8 | buf[13]; // Frames info.VBRFrames = buf[14] << 24 | buf[15] << 16 | buf[16] << 8 | buf[17]; // TOC // entries var tocEntries = buf[18] << 8 | buf[19]; var tocScale = buf[20] << 8 | buf[21]; var tocEntrySize = buf[22] << 8 | buf[23]; var tocFramesPerEntry = buf[24] << 8 | buf[25]; var tocSize = tocEntries * tocEntrySize; var toc = new byte[tocSize]; if (Read(62, toc) != tocSize) return null; return info; }
VBRInfo ParseXing(int offset) { VBRInfo info = new VBRInfo(); info.Channels = Channels; info.SampleRate = SampleRate; info.SampleCount = SampleCount; var buf = new byte[100]; if (Read(offset, buf, 0, 4) != 4) return null; offset += 4; var flags = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3]; // frame count if ((flags & 0x1) != 0) { if (Read(offset, buf, 0, 4) != 4) return null; offset += 4; info.VBRFrames = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3]; } // byte count if ((flags & 0x2) != 0) { if (Read(offset, buf, 0, 4) != 4) return null; offset += 4; info.VBRBytes = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3]; } // TOC if ((flags & 0x4) != 0) { // we're not using the TOC, so just discard it if (Read(offset, buf) != 100) return null; offset += 100; } // scale if ((flags & 0x8) != 0) { if (Read(offset, buf, 0, 4) != 4) return null; offset += 4; info.VBRQuality = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3]; } //// now look for a LAME header (note: if it isn't found, it doesn't fail the VBR parse) //do //{ // if (Read(offset, buf, 0, 20) != 20) break; // offset += 20; // // LAME tag revision: only 0 and 1 are valid // if ((buf[9] & 0xF0) > 0x10) break; // // VBR mode: 0-6, 8 & 9 are valid // var mode = buf[9] & 0xF; // if (mode == 7 || mode > 9) break; // // Lowpass filter value // var lowpass = buf[10] / 100.0; // // Replay Gain // var rgPeak = BitConverter.ToSingle(buf, 11); // var rgGainRadio = buf[15] << 8 | buf[16]; // var rgGain = buf[17] << 8 | buf[18]; //} while (false); return info; }
FrameBase FindNextFrame() { // if we've found the end, don't bother looking for anything else if (_endFound) return null; var freeFrame = _lastFree; var lastFrameStart = _readOffset; lock (_frameLock) { // read 3 bytes var syncBuf = new byte[4]; try { if (Read(_readOffset, syncBuf, 0, 4) == 4) { // now loop until a frame is found do { var sync = (uint)(syncBuf[0] << 24 | syncBuf[1] << 16 | syncBuf[2] << 8 | syncBuf[3]); lastFrameStart = _readOffset; // try ID3 first (for v2 frames) if (_id3Frame == null) { var f = ID3Frame.TrySync(sync); if (f != null) { if (f.Validate(_readOffset, this)) { if (!_canSeek) f.SaveBuffer(); _readOffset += f.Length; DiscardThrough(_readOffset, true); return _id3Frame = f; } } } // now look for a RIFF header if (_first == null && _riffHeaderFrame == null) { var f = RiffHeaderFrame.TrySync(sync); if (f != null) { if (f.Validate(_readOffset, this)) { _readOffset += f.Length; DiscardThrough(_readOffset, true); return _riffHeaderFrame = f; } } } // finally, just try for an MPEG frame var frame = MpegFrame.TrySync(sync); if (frame != null) { if (frame.Validate(_readOffset, this) && !(freeFrame != null && (frame.Layer != freeFrame.Layer || frame.Version != freeFrame.Version || frame.SampleRate != freeFrame.SampleRate || frame.BitRateIndex > 0 ) ) ) { if (!_canSeek) { frame.SaveBuffer(); DiscardThrough(_readOffset + frame.FrameLength, true); } _readOffset += frame.FrameLength; if (_first == null) { if (_vbrInfo == null && (_vbrInfo = frame.ParseVBR()) != null) { return FindNextFrame(); } else { frame.Number = 0; _first = _last = frame; } } else { if (frame.SampleCount != _first.SampleCount) { _mixedFrameSize = true; } frame.SampleOffset = _last.SampleCount + _last.SampleOffset; frame.Number = _last.Number + 1; _last = (_last.Next = frame); } if (frame.BitRateIndex == 0) { _lastFree = frame; } return frame; } } // if we've read MPEG frames and can't figure out what frame type we have, try looking for a new ID3 tag if (_last != null) { var f = ID3Frame.TrySync(sync); if (f != null) { if (f.Validate(_readOffset, this)) { if (!_canSeek) f.SaveBuffer(); // if it's a v1 tag, go ahead and parse it if (f.Version == 1) { _id3v1Frame = f; } else { // grrr... the ID3 2.4 spec says tags can be anywhere in the file and that later tags can override earlier ones... boo _id3Frame.Merge(f); } _readOffset += f.Length; DiscardThrough(_readOffset, true); return f; } } } // well, we didn't find anything, so rinse and repeat with the next byte ++_readOffset; if (_first == null || !_canSeek) DiscardThrough(_readOffset, true); Buffer.BlockCopy(syncBuf, 1, syncBuf, 0, 3); } while (Read(_readOffset + 3, syncBuf, 3, 1) == 1); } // move the "end of frame" marker for the last free format frame (in case we have one) // this is because we don't include the last four bytes otherwise lastFrameStart += 4; _endFound = true; return null; } finally { if (freeFrame != null) { freeFrame.Length = (int)(lastFrameStart - freeFrame.Offset); if (!_canSeek) { // gotta finish filling the buffer!! throw new InvalidOperationException("Free frames cannot be read properly from forward-only streams!"); } // if _lastFree hasn't changed (we got a non-MPEG frame), clear it out if (_lastFree == freeFrame) { _lastFree = null; } } } } }