protected Mp3XingBlock(byte[] frameBuf, int xix, Mp3Header header, string xingString) { this.buf = frameBuf; this.header = header; this.xingIx = xix; this.XingString = xingString; int ix = xingIx + 8; if (HasFrameCount) { this.FrameCount = ConvertTo.FromBig32ToInt32(frameBuf, ix); ix += 4; } if (HasSize) { this.XingSize = ConvertTo.FromBig32ToInt32(frameBuf, ix); ix += 4; } if (HasTableOfContents) { this.tocOffset = ix; ix += 100; } if (HasQualityIndicator) { this.QualityIndicator = ConvertTo.FromBig32ToInt32(frameBuf, ix); } }
public static Mp3XingBlock.Model Create(byte[] buf, Mp3Header header) { System.Diagnostics.Debug.Assert(header.IsMpegLayer3); int xix = header.XingOffset; string xingString = ConvertTo.FromAsciiToString(buf, xix, 4); if (xingString == "Info" || xingString == "Xing") { string lameString = ConvertTo.FromAsciiToString(buf, xix + 0x78, 9); if (lameString.StartsWith("LAME")) { return(new Mp3LameBlock.Model(buf, xix, header, xingString, lameString)); } else { return(new Mp3XingBlock.Model(buf, xix, header, xingString)); } } return(null); }
private void GetDiagnostics() { if (Data.Header.BitRate == null) { IssueModel.Add("Invalid bit rate."); } if (Data.Header.ChannelMode != Mp3ChannelMode.JointStereo) { IssueTags tags = Data.Header.ChannelMode == Mp3ChannelMode.Stereo? IssueTags.Overstandard : IssueTags.Substandard; IssueModel.Add($"Channel mode is {Data.Header.ChannelMode}.", Severity.Advisory, tags); } if (Data.Header.SampleRate < 44100) { IssueModel.Add($"Frequency is {Data.Header.SampleRate} Hz (expecting 44100 or better)", Severity.Advisory, IssueTags.Substandard); } else if (Data.Header.SampleRate > 44100) { IssueModel.Add($"Frequency is {Data.Header.SampleRate}", Severity.Advisory, IssueTags.Overstandard); } if (Data.Xing != null) { if (Data.Header.CrcProtectedBit == 0) { IssueModel.Add("Header not flagged for CRC protection.", Severity.Noise); } if (!Data.Xing.HasFrameCount) { IssueModel.Add("Missing XING frame count."); } if (!Data.Xing.HasSize) { IssueModel.Add("Missing XING file size."); } if (!Data.Xing.HasTableOfContents) { IssueModel.Add("Missing XING table of contents."); } else if (Data.Xing.IsTocCorrupt()) { IssueModel.Add("XING table of contents is corrupt."); } if (Data.Xing.HasQualityIndicator) { var qi = Data.Xing.QualityIndicator; if (qi < 0 || qi > 100) { IssueModel.Add($"Quality indicator of {qi} is out of range."); } else if (Data.Lame != null && Data.Lame.IsVbr && qi < 78) { IssueModel.Add($"VBR quality of {qi} is substandard.", Severity.Advisory, IssueTags.Substandard); } } } if (Data.Lame == null) { IssueModel.Add("Not a LAME encoding.", Severity.Advisory, IssueTags.Substandard); } else { var isBlessed = blessedLames.Any(item => item == Data.Lame.LameVersion); if (!isBlessed) { IssueModel.Add("LAME version is not favored.", Severity.Advisory, IssueTags.Substandard); } if (Data.Lame.LameSize != Data.MediaCount) { IssueModel.Add("Indicated LAME audio size incorrect or unrecognized tag block.", Severity.Warning); } if (Data.Lame.TagRevision == 0xF) { IssueModel.Add($"Tag revision {Data.Lame.TagRevision} invalid."); } if (Data.Lame.BitrateMethod == 0 || Data.Lame.BitrateMethod == 0xF) { IssueModel.Add($"Bitrate method {Data.Lame.BitrateMethod} invalid."); } if (Data.Lame.IsAbr) { IssueModel.Add("ABR encoding method is obsolete.", Severity.Advisory, IssueTags.Substandard); } if (Data.Lame.AudiophileReplayGain != 0) { IssueModel.Add($"Audiophile ReplayGain ({Data.Lame.AudiophileReplayGain}) usage is obsolete.", Severity.Advisory, IssueTags.Substandard); } if (Data.Lame.IsCbr && Mp3Header.IsBadCbr(Data.Header.MpegVersionBits, Data.Lame.MinBitRate)) { IssueModel.Add($"Minimum bit rate of {Data.Lame.MinBitRate} not valid.", Severity.Advisory, IssueTags.Substandard); } } if (Data.HasId3v1) { if (Data.HasId3v1Phantom) { IssueModel.Add("Has phantom ID3v1 tag block.", Severity.Warning, IssueTags.Fussy | IssueTags.HasId3v1, "Remove phantom ID3v1 tag block", RepairPhantomTag); } else { var minor = GetMinorOfV1(Data.id3v1Block); Severity sev = minor == 0? Severity.Warning : Severity.Noise; IssueModel.Add($"Has ID3v1.{minor} tags.", sev, IssueTags.HasId3v1); } } if (!Data.HasId3v2) { IssueModel.Add("Missing ID3v2 tags.", Severity.Trivia, IssueTags.Fussy | IssueTags.Substandard); } else { switch (Data.Id3v2Major) { case 2: IssueModel.Add("Has obsolete ID3v2.2 tags.", Severity.Warning, IssueTags.Fussy | IssueTags.Substandard); break; case 3: // Hunky dory! break; case 4: IssueModel.Add("Has jumped-the-shark ID3v2.4 tags.", Severity.Trivia); break; default: IssueModel.Add("Has ID3 tags of unknown version 2." + Data.Id3v2Major); break; } if (Data.Id3v2TagRepair != null) { IssueModel.Add($"ID3v2 tag size over by 1 (repair with {Data.Id3v2TagRepair}).", Severity.Warning, IssueTags.Fussy, "Patch EAC induced ID3v2 tag size error", RepairId3v2OffBy1); } } if (Data.HasApe) { IssueModel.Add("Has APE tags.", Severity.Trivia, IssueTags.HasApe); } if (Data.HasLyrics3) { IssueModel.Add("Has obsolete Lyrics3v2 block.", Severity.Advisory); } if (Data.DeadBytes != 0) { IssueModel.Add($"Dead space preceeds audio, size={Data.DeadBytes}", Severity.Warning, IssueTags.Substandard); } }
public Model(byte[] hdr, int xingIx, Mp3Header header, string xingText) => _data = new Mp3XingBlock(hdr, xingIx, header, xingText);
private Mp3LameBlock(byte[] buf, int xix, Mp3Header header, string xingString, string lameString) : base(buf, xix, header, xingString) => LameVersion = lameString;
public Model(byte[] buf, int hix, Mp3Header header, string xingString, string lameString) => base._data = new Mp3LameBlock(buf, hix, header, xingString, lameString);