/// <summary> /// Initializes a new instance of the <see cref="OggVorbis"/> class. /// </summary> /// <param name="path">The path.</param> public OggVorbis(string path) { using (FileStream stream = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read)) { try { int tmpID3v2Size = ID3v2.GetTagSize(stream); stream.Seek(tmpID3v2Size, SeekOrigin.Begin); byte[] oggMarker = stream.Read(4); if (ByteUtils.Compare(oggMarker, OGG_MARKER) == false) { throw new InvalidDataException("OggS marker not found"); } // Skip through Ogg page header to page_segments position stream.Seek(22, SeekOrigin.Current); // Skip segment_table int pageSegments = stream.Read1(); stream.Seek(pageSegments, SeekOrigin.Current); // Read vorbis header int packetType = stream.Read1(); if (packetType != 0x01) { throw new InvalidDataException("Vorbis identification header not found"); } byte[] vorbisMarker = stream.Read(6); if (ByteUtils.Compare(vorbisMarker, VORBIS_MARKER) == false) { throw new InvalidDataException("Vorbis marker not found"); } // Skip vorbis_version stream.Seek(4, SeekOrigin.Current); _channels = stream.Read1(); _frequency = stream.ReadInt32LittleEndian(); byte[] buf = new byte[251]; long size = stream.Length; // Get total number of samples _samples = 0; for (int index = 1; index <= 50 && _samples == 0; index++) { long dataIndex = size - ((251 - 10) * index) - 10; stream.Seek(dataIndex, SeekOrigin.Begin); stream.Read(buf, 0, 251); // Get number of PCM samples from last Ogg packet header for (int i = 251 - 10; i >= 0; i--) { bool headerFound = true; for (int j = 0; j < 4; j++) { if (buf[i + j] != OGG_MARKER[j]) { headerFound = false; break; } } if (headerFound) { stream.Seek(dataIndex + i + 6, SeekOrigin.Begin); stream.Read(buf, 0, 8); for (i = 0; i < 8; i++) { _samples += buf[i] << (8 * i); } break; } } } if (_samples == 0) { throw new InvalidDataException("Could not position to last frame"); } _totalSeconds = _samples / (decimal)_frequency; _bitrate = (size - tmpID3v2Size) / _totalSeconds / 125.0m; } catch (Exception ex) { throw new Exception("Invalid Ogg-Vorbis file; stream may be corrupt", ex); } } }
/// <summary> /// Initializes a new instance of the <see cref="MonkeysAudio"/> class. /// </summary> /// <param name="path">The path.</param> public MonkeysAudio(string path) { using (FileStream stream = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read)) { // Skip ID3v2 tag int tmpID3v2TagSize = ID3v2.GetTagSize(stream); int tmpID3v1TagSize = ID3v1.GetTagSize(stream); int tmpAPEv2TagSize = APEv2.GetTagSize(stream); stream.Seek(tmpID3v2TagSize, SeekOrigin.Begin); byte[] identifier = stream.Read(4); if (ByteUtils.Compare(identifier, MAC_IDENTIFIER, 4) == false) { throw new InvalidDataException("Invalid Monkey's Audio file"); } byte[] buf = stream.Read(4); _version = buf[0] + (buf[1] << 8); int blocksPerFrame; int finalBlocks; if (_version >= 3980 && _version <= 3990) { buf = stream.Read(4); int descriptorLength = buf[0] + (buf[1] << 8) + (buf[2] << 16) + (buf[3] << 24); stream.Seek(descriptorLength - 12, SeekOrigin.Current); // skip DESCRIPTOR buf = stream.Read(4); _compressionLevel = buf[0] + (buf[1] << 8); blocksPerFrame = stream.ReadInt32LittleEndian(); finalBlocks = stream.ReadInt32LittleEndian(); _frames = stream.ReadInt32LittleEndian(); buf = stream.Read(4); // skip bits per sample _channels = buf[2] + (buf[3] << 8); _frequency = stream.ReadInt32LittleEndian(); } else if (_version <= 3970) { // TODO: This section needs work _compressionLevel = buf[2] + (buf[3] << 8); buf = stream.Read(24); // skip format flags _channels = buf[2] + (buf[3] << 8); _frequency = buf[4] + (buf[5] << 8) + (buf[6] << 16) + (buf[7] << 32); if (_version >= 3950) { blocksPerFrame = 73728 * 4; } else if (_version >= 3900 || (_version >= 3800 && _compressionLevel == COMPRESSION_LEVEL_EXTRA_HIGH)) { blocksPerFrame = 73728; } else { blocksPerFrame = 9216; } // TODO: This is definitely f****d up finalBlocks = buf[0] + (buf[1] << 8) + (buf[2] << 16) + (buf[3] << 24); _frames = buf[0] + (buf[1] << 8) + (buf[2] << 16) + (buf[3] << 24); } else { throw new NotImplementedException(string.Format("MAC {0:0.00} not supported", _version / 1000.0)); } long totalBlocks = ((_frames - 1) * blocksPerFrame) + finalBlocks; long totalSize = stream.Length - stream.Position - tmpAPEv2TagSize - tmpID3v1TagSize; _totalSeconds = totalBlocks / (decimal)_frequency; _bitrate = totalSize / (_totalSeconds * 125.0m); } }
/// <summary> /// Initializes a new instance of the <see cref="Mpeg"/> class. /// </summary> /// <param name="path">The full path of the file.</param> /// <param name="calculateBitrate">if set to <c>true</c> the bitrate will be calculated before the constructor returns.</param> public Mpeg(string path, bool calculateBitrate) { _fileName = path; using (FileStream stream = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read)) { int tmpID3v2TagSize = ID3v2.GetTagSize(stream); stream.Seek(tmpID3v2TagSize, SeekOrigin.Begin); byte[] tmpFrameHeader = new byte[4]; bool acceptNullSamples = false; while (true) { int tmpByte = stream.ReadByte(); // keep as ReadByte while (tmpByte != 0xFF && tmpByte != -1) { tmpByte = stream.ReadByte(); // keep as ReadByte } if (tmpByte == -1) { if (acceptNullSamples) { throw new InvalidDataException(string.Format("'{0}': Can't find frame sync", path)); } stream.Seek(tmpID3v2TagSize, SeekOrigin.Begin); acceptNullSamples = true; continue; } tmpFrameHeader[0] = (byte)tmpByte; // Get frame header if (stream.Read(tmpFrameHeader, 1, 3) != 3) { throw new InvalidDataException(string.Format("'{0}': Invalid MPEG file; end of stream reached", path)); } // No sync if ((tmpFrameHeader[1] >> 5) != 0x07 || ((tmpFrameHeader[1] >> 1) & 0x03) == 0) // 2/18/05 - ignore reserved layer { stream.Seek(-3, SeekOrigin.Current); } else if (tmpFrameHeader[1] == 0xFF || ((tmpFrameHeader[1] >> 3) & 0x03) == 1) // 2/19/05 - more bad data { stream.Seek(-3, SeekOrigin.Current); } else { int tmpMpegID = (tmpFrameHeader[1] >> 3) & 0x03; int tmpLayerNum = (tmpFrameHeader[1] >> 1) & 0x03; int tmpFrequency = GetFrequency((MpegVersion)tmpMpegID, (tmpFrameHeader[2] >> 2) & 0x03); // Check for invalid frequency if (tmpFrequency == 0) { stream.Seek(-3, SeekOrigin.Current); continue; } int tmpSamplesPerFrame = GetSamplesPerFrame((MpegVersion)tmpMpegID, (MpegLayer)tmpLayerNum); int tmpUsesPadding = (tmpFrameHeader[2] >> 1) & 0x01; double tmpFrameSizeConst = 125.0 * tmpSamplesPerFrame / tmpFrequency; int tmpPaddingSize = (tmpLayerNum == 3 ? 4 : 1); int tmpBitrateIndex = tmpFrameHeader[2] >> 4; // Check for invalid values if (tmpBitrateIndex < 1 || tmpBitrateIndex > 14 || tmpLayerNum == 0) { stream.Seek(-3, SeekOrigin.Current); continue; } int tmpFrameBitrate = GetBitrate((MpegVersion)tmpMpegID, (MpegLayer)tmpLayerNum, tmpBitrateIndex); int tmpFrameSize = (int)(tmpFrameBitrate * tmpFrameSizeConst) + (tmpUsesPadding * tmpPaddingSize); _headerOffset = stream.Position - 4; if (tmpFrameSize < 8) { stream.Seek(-3, SeekOrigin.Current); continue; } // 7/21/05 - Check for 0x00 or 0xFF at end of last frame // this sucks for tracks that start with silence if (_headerOffset >= 1 && !acceptNullSamples) // if (ftell(fp) >= 5) { stream.Seek(-5, SeekOrigin.Current); byte tmpLastByte = stream.Read1(); stream.Seek(4, SeekOrigin.Current); if (tmpFrameBitrate != 320 && (tmpLastByte == 0x00 || tmpLastByte == 0xFF)) { // 7/31/05 // may be a valid frame - skip its contents to prevent false sync long tmpNewPosition = _headerOffset + tmpFrameSize; if (tmpFrameSize == 0) { tmpNewPosition++; } stream.Seek(tmpNewPosition, SeekOrigin.Begin); continue; } } /*if (BR == 0 || FrameSizeConst == 0) * { * startpos = HeaderOffset+1; * fseek(fp, startpos, SEEK_SET); * continue; * }*/ stream.Seek(_headerOffset + tmpFrameSize, SeekOrigin.Begin); if (stream.Read1() == 0xFF) { fh1 = stream.Read1(); fh2 = stream.Read1(); if (tmpFrameHeader[1] == fh1 && (tmpFrameHeader[2] & 0x0D) == (fh2 & 0x0D)) { // header found break; } } stream.Seek(_headerOffset + 1, SeekOrigin.Begin); continue; } } _mpegVersion = (MpegVersion)((tmpFrameHeader[1] >> 3) & 0x03); _mpegLayer = (MpegLayer)((tmpFrameHeader[1] >> 1) & 0x03); _frequency = GetFrequency(_mpegVersion, (tmpFrameHeader[2] >> 2) & 0x03); if (_frequency == 0) { throw new InvalidDataException(String.Format("'{0}'; cannot determine frequency", path)); } _isPrivate = ((tmpFrameHeader[2] & 0x01) == 0x01); _samplesPerFrame = GetSamplesPerFrame(_mpegVersion, _mpegLayer); _frameSizeConst = 125.0 * _samplesPerFrame / _frequency; _paddingSizeConst = (_mpegLayer == MpegLayer.Layer1 ? 4 : 1); _isCopyright = (((tmpFrameHeader[3] >> 3) & 0x01) == 0x01); _isOriginal = (((tmpFrameHeader[3] >> 2) & 0x01) == 0x01); //tmpModeExtension = (FH[3] >> 4) & 0x03; // not interested, only used in joint-stereo //_mpegEmphasis = (MpegEmphasis)(tmpFrameHeader[3] & 0x03); if ((tmpFrameHeader[3] >> 6) == 3) { _channels = 1; // Single Channel } else { _channels = 2; } // Read LAME Info Tag bool tmpHasLameInfoTag = false; stream.Seek(tmpID3v2TagSize + 36, SeekOrigin.Begin); Byte[] buf = stream.Read(4); if (ByteUtils.Compare(buf, INFO_MARKER)) // CBR { tmpHasLameInfoTag = true; _isVBR = false; } else if (ByteUtils.Compare(buf, XING_MARKER)) // VBR { tmpHasLameInfoTag = true; _isVBR = true; } if (tmpHasLameInfoTag) { stream.Seek(4, SeekOrigin.Current); int tmpFrames = stream.ReadInt32(); uint tmpBytes = (uint)stream.ReadInt32(); if (tmpFrames > 256 && tmpBytes > 50000) { decimal tmpBitrate = tmpBytes / 125.0m / (tmpFrames * _samplesPerFrame / (decimal)_frequency); if (tmpBitrate <= 320 && tmpBitrate >= 32) { _frames = tmpFrames; _bitrate = tmpBitrate; _totalSeconds = (tmpBytes / 125.0m) / _bitrate; } } } // TODO: Take these 2 lines out /*fs.Position = 0; * CalculateBitrate(fs, null);*/ if (calculateBitrate) { if (_bitrate == 0 || _isVBR == null || _frames == 0 || _totalSeconds == 0) { stream.Position = 0; CalculateBitrate(stream, null); } } } }
private void CalculateBitrate(Stream stream, CInterestedFrames InterestedFrames) { int totalTagSize = ID3v2.GetTagSize(stream); totalTagSize += ID3v1.GetTagSize(stream); totalTagSize += APEv2.GetTagSize(stream); Int64 audioLength = stream.Length - totalTagSize; _bitrate = 0; _isVBR = null; _frames = 0; _totalSeconds = 0; String step = ""; try { int BR, Padding; int FrameSize; int TotalBR = 0; int FrameOffset = 0; //Int64 TagOffset = 0; bool bTrusting = true; bool ignoreall = false; Byte[] FH = new Byte[4]; bool mPerfect = true; stream.Position = _headerOffset; // if (_headerOffset > 0) // { // TagOffset = _headerOffset; // } int offset = 0; int frameCount = 0; int FirstBR = 0; int audioDataSize = (int)(stream.Length - _headerOffset); Byte[] audioData = new Byte[audioDataSize]; //Int64 startoffset = stream.Position; int BufLen = stream.Read(audioData, 0, audioDataSize); while (offset < BufLen - 16 && !ignoreall) { bool reservedlayer = false; // Find FrameSync if (FindFrameSync(FH, audioData, BufLen, ref FrameOffset, ref offset, ref mPerfect, ref ignoreall, ref bTrusting, ref reservedlayer)) { FrameOffset = 0; int bitrateIndex = FH[2] >> 4; if (bitrateIndex <= 0 || bitrateIndex >= 15) { offset -= 3; continue; } Padding = (FH[2] >> 1) & 0x01; BR = GetBitrate(_mpegVersion, _mpegLayer, bitrateIndex); if (BR == 0 || BR % 8 != 0) { offset -= 3; continue; } //step = "last good frame @ " + String(startoffset + offset - 4) + ", frame " + // String(_frames + 1); // todo: put back later /*if (InterestedFrames != NULL) * { * if (((_frames + 1) * _samplesperframe / (float)_Frequency) * 75.0 >= InterestedFrames->CurrentFrame()) * { * if (_frames == 0 || InterestedFrames->NoAccomodation) * { * InterestedFrames->SetCurrentByteOffset(startoffset + offset - 4); * InterestedFrames->SetCurrentFrameOffset(_frames); * } * InterestedFrames->SetCurrentByteEndOffset(startoffset + offset - 4); * InterestedFrames->Cur += 1; * } * else * { * InterestedFrames->SetCurrentByteOffset(startoffset + offset - 4); * InterestedFrames->SetCurrentFrameOffset(_frames); * } * }*/ if (_isVBR != true) { if (TotalBR == 0) { FirstBR = BR; } else if (BR != FirstBR) { _isVBR = true; } } TotalBR += BR; FrameSize = (int)(BR * _frameSizeConst + Padding * _paddingSizeConst); offset += FrameSize - 4; frameCount++; } }// end while if (frameCount == 0) { throw new InvalidDataException(String.Format("No frames found in {0}", _fileName)); } _frames = frameCount; if (_isVBR == null) { _bitrate = FirstBR; _isVBR = false; } else { _bitrate = TotalBR / _frames; } if (_bitrate == 0) { throw new InvalidDataException(String.Format("Error determining bitrate: {0}", _fileName)); } _totalSeconds = (audioLength / 125.0m) / _bitrate; } catch (Exception ex) { throw new Exception(String.Format("Error calculating bitrate; {0}", step), ex); } }
private readonly int _channels = 2; // TODO /// <summary> /// Initializes a new instance of the <see cref="Musepack"/> class. /// </summary> /// <param name="path">The path of the file.</param> public Musepack(string path) { using (FileStream stream = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read)) { // Skip ID3v2 tag int tmpID3v2TagSize = ID3v2.GetTagSize(stream); int tmpID3v1TagSize = ID3v1.GetTagSize(stream); int tmpAPEv2TagSize = APEv2.GetTagSize(stream); stream.Seek(tmpID3v2TagSize, SeekOrigin.Begin); _streamVersion = 0; byte[] byteArray = stream.Read(32); int[] integerArray = new int[8]; for (int i = 0; i < 8; i++) { integerArray[i] = (byteArray[i * 4]) + (byteArray[i * 4 + 1] << 8) + (byteArray[i * 4 + 2] << 16) + (byteArray[i * 4 + 3] << 24); } // Size TODO - ignore Lyrics3 long audioDataLength = stream.Length - tmpID3v2TagSize - tmpID3v1TagSize - tmpAPEv2TagSize; // Stream version if (integerArray[0] == STREAM_VERSION_70_ID) { _streamVersion = 7; } else if (integerArray[0] == STREAM_VERSION_71_ID) { _streamVersion = 7.1m; } else { switch ((byteArray[1] % 32) / 2) { case 3: _streamVersion = 4; break; case 7: _streamVersion = 5; break; case 11: _streamVersion = 6; break; } } if (_streamVersion == 0) { throw new InvalidDataException("Unrecognized MPC stream"); } // Sample rate _frequency = _sampleRates[byteArray[10] & 0x03]; // Channels if (_streamVersion == 7 || _streamVersion == 7.1m) { if ((byteArray[11] % 128) < 64) { _mode = "Stereo"; } else { _mode = "Joint Stereo"; } } else { if ((byteArray[2] % 128) == 0) { _mode = "Stereo"; } else { _mode = "Joint Stereo"; } } // Frames if (_streamVersion == 4) { _frames = integerArray[1] >> 16; } else { _frames = integerArray[1]; } _totalSeconds = _frames * 1152 / (decimal)_frequency; _bitrate = (audioDataLength / _totalSeconds) / 125.0m; } }
/// <summary> /// Initializes a new instance of the <see cref="Flac"/> class. /// </summary> /// <param name="path">The path of the file.</param> public Flac(string path) { try { using (FileStream stream = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read)) { // Skip ID3v2 tag int tmpID3v2TagSize = ID3v2.GetTagSize(stream); int tmpID3v1TagSize = ID3v1.GetTagSize(stream); int tmpAPEv2TagSize = APEv2.GetTagSize(stream); stream.Seek(tmpID3v2TagSize, SeekOrigin.Begin); // Read flac marker byte[] flacMarker = new Byte[4]; stream.Read(flacMarker, 0, 4); if (ByteUtils.Compare(flacMarker, FLAC_MARKER) == false) { throw new InvalidDataException("No header found"); } // skip frame header and stuff we're not interested in stream.Seek(14, SeekOrigin.Current); byte[] buf = stream.Read(8); _frequency = (buf[0] << 12) + (buf[1] << 4) + (buf[2] >> 4); _channels = ((buf[2] >> 1) & 0x03) + 1; _samples = ((buf[3] & 0x0F) << 32) + (buf[4] << 24) + (buf[5] << 16) + (buf[6] << 8) + buf[7]; _totalSeconds = _samples / (decimal)_frequency; // Find first sync // TODO: There's probably a better way to do this.. also an embedded PICTURE might // cause a false sync. Not high priority since it will only cause a slight error // in bitrate calculation if a false sync is found. int c = stream.ReadByte(); // keep as ReadByte while (c != -1) { if (c == 0xFF) { c = stream.ReadByte(); // keep as ReadByte if (c >= 0xF8 && c <= 0xFB) { break; } } else { c = stream.ReadByte(); // keep as ReadByte } } if (c == -1) { throw new InvalidDataException("No sync found"); } long startaudio = stream.Position; long totalsize = stream.Length - startaudio - tmpAPEv2TagSize - tmpID3v1TagSize; _bitrate = totalsize / (_totalSeconds * 125); } } catch (InvalidDataException ex) { throw new InvalidDataException(String.Format("Cannot read FLAC file '{0}'", path), ex); } }