Initial commit
This commit is contained in:
commit
262601edb8
2025 files changed
+218754
No files matched your search
@@ -0,0 +1,275 @@
|
||||
//
|
||||
// File.cs: Provides tagging and properties support for Monkey's Audio APE
|
||||
// files.
|
||||
//
|
||||
// Author:
|
||||
// Helmut Wahrmann
|
||||
//
|
||||
// Copyright (C) 2007 Helmut Wahrmann
|
||||
// Copyright (C) 2007 Brian Nickel
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License version
|
||||
// 2.1 as published by the Free Software Foundation.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
// USA
|
||||
//
|
||||
|
||||
using System;
|
||||
|
||||
namespace TagLib.Ape
|
||||
{
|
||||
/// <summary>
|
||||
/// This class extends <see cref="TagLib.NonContainer.File" /> to
|
||||
/// provide tagging and properties support for Monkey's Audio APE
|
||||
/// files.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A <see cref="TagLib.Ape.Tag" /> will be added automatically to
|
||||
/// any file that doesn't contain one. This change does not effect
|
||||
/// the physical file until <see cref="TagLib.File.Save" /> is called and can be
|
||||
/// reversed using the following method:
|
||||
/// <code>file.RemoveTags (file.TagTypes & ~file.TagTypesOnDisk);</code>
|
||||
/// </remarks>
|
||||
[SupportedMimeType ("taglib/ape", "ape")]
|
||||
[SupportedMimeType ("audio/x-ape")]
|
||||
[SupportedMimeType ("audio/ape")]
|
||||
[SupportedMimeType ("application/x-ape")]
|
||||
public class File : TagLib.NonContainer.File
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Contains the block with the audio header.
|
||||
/// </summary>
|
||||
ByteVector header_block;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified path in the local file
|
||||
/// system and specified read style.
|
||||
/// </summary>
|
||||
/// <param name="path">
|
||||
/// A <see cref="string" /> object containing the path of the
|
||||
/// file to use in the new instance.
|
||||
/// </param>
|
||||
/// <param name="propertiesStyle">
|
||||
/// A <see cref="ReadStyle" /> value specifying at what level
|
||||
/// of accuracy to read the media properties, or <see
|
||||
/// cref="ReadStyle.None" /> to ignore the properties.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="path" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
public File (string path, ReadStyle propertiesStyle)
|
||||
: base (path, propertiesStyle)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified path in the local file
|
||||
/// system with an average read style.
|
||||
/// </summary>
|
||||
/// <param name="path">
|
||||
/// A <see cref="string" /> object containing the path of the
|
||||
/// file to use in the new instance.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="path" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
public File (string path)
|
||||
: base (path)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified file abstraction and
|
||||
/// specified read style.
|
||||
/// </summary>
|
||||
/// <param name="abstraction">
|
||||
/// A <see cref="TagLib.File.IFileAbstraction" /> object to use when
|
||||
/// reading from and writing to the file.
|
||||
/// </param>
|
||||
/// <param name="propertiesStyle">
|
||||
/// A <see cref="ReadStyle" /> value specifying at what level
|
||||
/// of accuracy to read the media properties, or <see
|
||||
/// cref="ReadStyle.None" /> to ignore the properties.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="abstraction" /> is <see langword="null"
|
||||
/// />.
|
||||
/// </exception>
|
||||
public File (IFileAbstraction abstraction, ReadStyle propertiesStyle)
|
||||
: base (abstraction, propertiesStyle)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified file abstraction with an
|
||||
/// average read style.
|
||||
/// </summary>
|
||||
/// <param name="abstraction">
|
||||
/// A <see cref="TagLib.File.IFileAbstraction" /> object to use when
|
||||
/// reading from and writing to the file.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="abstraction" /> is <see langword="null"
|
||||
/// />.
|
||||
/// </exception>
|
||||
public File (IFileAbstraction abstraction)
|
||||
: base (abstraction)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Gets a tag of a specified type from the current instance,
|
||||
/// optionally creating a new tag if possible.
|
||||
/// </summary>
|
||||
/// <param name="type">
|
||||
/// A <see cref="TagLib.TagTypes" /> value indicating the
|
||||
/// type of tag to read.
|
||||
/// </param>
|
||||
/// <param name="create">
|
||||
/// A <see cref="bool" /> value specifying whether or not to
|
||||
/// try and create the tag if one is not found.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="Tag" /> object containing the tag that was
|
||||
/// found in or added to the current instance. If no
|
||||
/// matching tag was found and none was created, <see
|
||||
/// langword="null" /> is returned.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// If a <see cref="TagLib.Id3v2.Tag" /> is added to the
|
||||
/// current instance, it will be placed at the start of the
|
||||
/// file. On the other hand, <see cref="TagLib.Id3v1.Tag" />
|
||||
/// <see cref="TagLib.Ape.Tag" /> will be added to the end of
|
||||
/// the file. All other tag types will be ignored.
|
||||
/// </remarks>
|
||||
public override TagLib.Tag GetTag (TagTypes type, bool create)
|
||||
{
|
||||
TagLib.Tag t = (Tag as TagLib.NonContainer.Tag)
|
||||
.GetTag (type);
|
||||
|
||||
if (t != null || !create)
|
||||
return t;
|
||||
|
||||
switch (type) {
|
||||
case TagTypes.Id3v1:
|
||||
return EndTag.AddTag (type, Tag);
|
||||
|
||||
case TagTypes.Id3v2:
|
||||
return StartTag.AddTag (type, Tag);
|
||||
|
||||
case TagTypes.Ape:
|
||||
return EndTag.AddTag (type, Tag);
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
/// <summary>
|
||||
/// Reads format specific information at the start of the
|
||||
/// file.
|
||||
/// </summary>
|
||||
/// <param name="start">
|
||||
/// A <see cref="long" /> value containing the seek position
|
||||
/// at which the tags end and the media data begins.
|
||||
/// </param>
|
||||
/// <param name="propertiesStyle">
|
||||
/// A <see cref="ReadStyle" /> value specifying at what level
|
||||
/// of accuracy to read the media properties, or <see
|
||||
/// cref="ReadStyle.None" /> to ignore the properties.
|
||||
/// </param>
|
||||
protected override void ReadStart (long start, ReadStyle propertiesStyle)
|
||||
{
|
||||
if (header_block != null &&
|
||||
(propertiesStyle & ReadStyle.Average) == 0)
|
||||
return;
|
||||
|
||||
Seek (start);
|
||||
header_block = ReadBlock ((int)StreamHeader.Size);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads format specific information at the end of the
|
||||
/// file.
|
||||
/// </summary>
|
||||
/// <param name="end">
|
||||
/// A <see cref="long" /> value containing the seek position
|
||||
/// at which the media data ends and the tags begin.
|
||||
/// </param>
|
||||
/// <param name="propertiesStyle">
|
||||
/// A <see cref="ReadStyle" /> value specifying at what level
|
||||
/// of accuracy to read the media properties, or <see
|
||||
/// cref="ReadStyle.None" /> to ignore the properties.
|
||||
/// </param>
|
||||
protected override void ReadEnd (long end, ReadStyle propertiesStyle)
|
||||
{
|
||||
// Make sure we have an APE tag.
|
||||
GetTag (TagTypes.Ape, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the audio properties from the file represented by
|
||||
/// the current instance.
|
||||
/// </summary>
|
||||
/// <param name="start">
|
||||
/// A <see cref="long" /> value containing the seek position
|
||||
/// at which the tags end and the media data begins.
|
||||
/// </param>
|
||||
/// <param name="end">
|
||||
/// A <see cref="long" /> value containing the seek position
|
||||
/// at which the media data ends and the tags begin.
|
||||
/// </param>
|
||||
/// <param name="propertiesStyle">
|
||||
/// A <see cref="ReadStyle" /> value specifying at what level
|
||||
/// of accuracy to read the media properties, or <see
|
||||
/// cref="ReadStyle.None" /> to ignore the properties.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="TagLib.Properties" /> object describing the
|
||||
/// media properties of the file represented by the current
|
||||
/// instance.
|
||||
/// </returns>
|
||||
protected override Properties ReadProperties (long start, long end, ReadStyle propertiesStyle)
|
||||
{
|
||||
StreamHeader header = new StreamHeader (header_block,
|
||||
end - start);
|
||||
|
||||
return new Properties (TimeSpan.Zero, header);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6bd919f3cebce9e6b94eb2887772bf8d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,392 @@
|
||||
//
|
||||
// Footer.cs: Provides a representation of an APEv2 tag footer which can be read
|
||||
// from and written to disk.
|
||||
//
|
||||
// Author:
|
||||
// Brian Nickel (brian.nickel@gmail.com)
|
||||
//
|
||||
// Original Source:
|
||||
// apefooter.cpp from TagLib
|
||||
//
|
||||
// Copyright (C) 2005-2007 Brian Nickel
|
||||
// Copyright (C) 2004 Allan Sandfeld Jensen (Original Implementation)
|
||||
// copyright (C) 2002, 2003 Scott Wheeler (Original Implementation)
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License version
|
||||
// 2.1 as published by the Free Software Foundation.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
// USA
|
||||
//
|
||||
|
||||
using System;
|
||||
|
||||
namespace TagLib.Ape
|
||||
{
|
||||
#region Enums
|
||||
|
||||
/// <summary>
|
||||
/// Indicates the flags applied to a <see cref="Footer" /> object.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum FooterFlags : uint
|
||||
{
|
||||
/// <summary>
|
||||
/// The tag lacks a footer object.
|
||||
/// </summary>
|
||||
FooterAbsent = 0x40000000,
|
||||
|
||||
/// <summary>
|
||||
/// The footer is actually a header.
|
||||
/// </summary>
|
||||
IsHeader = 0x20000000,
|
||||
|
||||
/// <summary>
|
||||
/// The tag contains a header.
|
||||
/// </summary>
|
||||
HeaderPresent = 0x80000000
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This structure provides a representation of an APEv2 tag footer
|
||||
/// which can be read from and written to disk.
|
||||
/// </summary>
|
||||
public struct Footer : IEquatable<Footer>
|
||||
{
|
||||
#region Private Properties
|
||||
|
||||
/// <summary>
|
||||
/// Contains the APE tag version.
|
||||
/// </summary>
|
||||
readonly uint version;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Static Fields
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the size of an APEv2 footer.
|
||||
/// </summary>
|
||||
public const uint Size = 32;
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the identifier used find an APEv2 footer in a
|
||||
/// file.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// "<c>APETAGEX</c>"
|
||||
/// </value>
|
||||
public static readonly ReadOnlyByteVector FileIdentifier = "APETAGEX";
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="Footer" /> by reading it from raw footer data.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object containing the raw
|
||||
/// data to build the new instance from.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="data" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <exception cref="CorruptFileException">
|
||||
/// <paramref name="data" /> is smaller than <see
|
||||
/// cref="Size" /> or does not begin with <see
|
||||
/// cref="FileIdentifier" />.
|
||||
/// </exception>
|
||||
public Footer (ByteVector data)
|
||||
{
|
||||
if (data == null)
|
||||
throw new ArgumentNullException (nameof (data));
|
||||
|
||||
if (data.Count < Size)
|
||||
throw new CorruptFileException ("Provided data is smaller than object size.");
|
||||
|
||||
if (!data.StartsWith (FileIdentifier))
|
||||
throw new CorruptFileException ("Provided data does not start with File Identifier");
|
||||
|
||||
version = data.Mid (8, 4).ToUInt (false);
|
||||
TagSize = data.Mid (12, 4).ToUInt (false);
|
||||
ItemCount = data.Mid (16, 4).ToUInt (false);
|
||||
Flags = (FooterFlags)data.Mid (20, 4).ToUInt (false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets the version of APE tag described by the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="uint" /> value containing the version of the
|
||||
/// APE tag described by the current instance.
|
||||
/// </value>
|
||||
public uint Version {
|
||||
get { return version == 0 ? 2000 : version; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the flags that apply to the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A bitwise combined <see cref="FooterFlags" /> value
|
||||
/// containing the flags that apply to the current instance.
|
||||
/// </value>
|
||||
public FooterFlags Flags { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the number of items in the tag represented
|
||||
/// by the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="uint" /> value containing the number of
|
||||
/// items in the tag represented by the current instance.
|
||||
/// </value>
|
||||
public uint ItemCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the size of the tag represented by the current
|
||||
/// instance, including the footer but excluding the header
|
||||
/// if applicable.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="uint" /> value containing the size of the
|
||||
/// tag represented by the current instance.
|
||||
/// </value>
|
||||
public uint TagSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the complete size of the tag represented by the
|
||||
/// current instance, including the header and footer.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="uint" /> value containing the size of the
|
||||
/// tag represented by the current instance.
|
||||
/// </value>
|
||||
public uint CompleteTagSize {
|
||||
get {
|
||||
return TagSize + ((Flags &
|
||||
FooterFlags.HeaderPresent) != 0 ?
|
||||
Size : 0);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Renders the current instance as an APE tag footer.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVector" /> object containing the
|
||||
/// rendered version of the current instance.
|
||||
/// </returns>
|
||||
public ByteVector RenderFooter ()
|
||||
{
|
||||
return Render (false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renders the current instance as an APE tag header.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVector" /> object containing the
|
||||
/// rendered version of the current instance or an empty
|
||||
/// <see cref="ByteVector" /> object if <see cref="Flags" />
|
||||
/// does not include <see cref="FooterFlags.HeaderPresent"
|
||||
/// />.
|
||||
/// </returns>
|
||||
public ByteVector RenderHeader ()
|
||||
{
|
||||
return (Flags & FooterFlags.HeaderPresent) != 0 ? Render (true) : new ByteVector ();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// Renders the current instance as either an APE tag header
|
||||
/// or footer.
|
||||
/// </summary>
|
||||
/// <param name="isHeader">
|
||||
/// A <see cref="bool" /> value indicating whether or not the
|
||||
/// current instance is to be rendered as a header.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVector" /> object containing the
|
||||
/// rendered version of the current instance.
|
||||
/// </returns>
|
||||
ByteVector Render (bool isHeader)
|
||||
{
|
||||
var v = new ByteVector {
|
||||
|
||||
// add the file identifier -- "APETAGEX"
|
||||
FileIdentifier,
|
||||
|
||||
// add the version number -- we always render a 2.000
|
||||
// tag regardless of what the tag originally was.
|
||||
ByteVector.FromUInt (2000, false),
|
||||
|
||||
// add the tag size
|
||||
ByteVector.FromUInt (TagSize, false),
|
||||
|
||||
// add the item count
|
||||
ByteVector.FromUInt (ItemCount, false)
|
||||
};
|
||||
|
||||
// render and add the flags
|
||||
uint flags = 0;
|
||||
|
||||
if ((Flags & FooterFlags.HeaderPresent) != 0)
|
||||
flags |= (uint)FooterFlags.HeaderPresent;
|
||||
|
||||
// footer is always present
|
||||
if (isHeader)
|
||||
flags |= (uint)FooterFlags.IsHeader;
|
||||
else
|
||||
flags &= (uint)~FooterFlags.IsHeader;
|
||||
|
||||
v.Add (ByteVector.FromUInt (flags, false));
|
||||
|
||||
// add the reserved 64bit
|
||||
v.Add (ByteVector.FromULong (0));
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region IEquatable
|
||||
|
||||
/// <summary>
|
||||
/// Generates a hash code for the current instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="int" /> value containing the hash code for
|
||||
/// the current instance.
|
||||
/// </returns>
|
||||
public override int GetHashCode ()
|
||||
{
|
||||
unchecked {
|
||||
return (int)((uint)Flags ^ TagSize ^ ItemCount ^ version);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether or not the current instance is equal to
|
||||
/// another object.
|
||||
/// </summary>
|
||||
/// <param name="other">
|
||||
/// A <see cref="object" /> to compare to the current
|
||||
/// instance.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="bool" /> value indicating whether or not the
|
||||
/// current instance is equal to <paramref name="other" />.
|
||||
/// </returns>
|
||||
/// <seealso cref="M:System.IEquatable`1.Equals" />
|
||||
public override bool Equals (object other)
|
||||
{
|
||||
if (!(other is Footer))
|
||||
return false;
|
||||
|
||||
return Equals ((Footer)other);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether or not the current instance is equal to
|
||||
/// another instance of <see cref="Footer" />.
|
||||
/// </summary>
|
||||
/// <param name="other">
|
||||
/// A <see cref="Footer" /> object to compare to the current
|
||||
/// instance.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="bool" /> value indicating whether or not the
|
||||
/// current instance is equal to <paramref name="other" />.
|
||||
/// </returns>
|
||||
/// <seealso cref="M:System.IEquatable`1.Equals" />
|
||||
public bool Equals (Footer other)
|
||||
{
|
||||
return Flags == other.Flags &&
|
||||
TagSize == other.TagSize &&
|
||||
ItemCount == other.ItemCount &&
|
||||
version == other.version;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether or not two instances of <see cref="Footer"
|
||||
/// /> are equal to eachother.
|
||||
/// </summary>
|
||||
/// <param name="first">
|
||||
/// The first <see cref="Footer" /> object to compare.
|
||||
/// </param>
|
||||
/// <param name="second">
|
||||
/// The second <see cref="Footer" /> object to compare.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// <see langword="true" /> if <paramref name="first" /> is
|
||||
/// equal to <paramref name="second" />. Otherwise, <see
|
||||
/// langword="false" />.
|
||||
/// </returns>
|
||||
public static bool operator == (Footer first, Footer second)
|
||||
{
|
||||
return first.Equals (second);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether or not two instances of <see cref="Footer"
|
||||
/// /> are unequal to eachother.
|
||||
/// </summary>
|
||||
/// <param name="first">
|
||||
/// The first <see cref="Footer" /> object to compare.
|
||||
/// </param>
|
||||
/// <param name="second">
|
||||
/// The second <see cref="Footer" /> object to compare.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// <see langword="true" /> if <paramref name="first" /> is
|
||||
/// unequal to <paramref name="second" />. Otherwise, <see
|
||||
/// langword="false" />.
|
||||
/// </returns>
|
||||
public static bool operator != (Footer first, Footer second)
|
||||
{
|
||||
return !first.Equals (second);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3fd643b62da0d63f89725b4266c74752
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,500 @@
|
||||
//
|
||||
// Item.cs: Provides a representation of an APEv2 tag item which can be read
|
||||
// from and written to disk.
|
||||
//
|
||||
// Author:
|
||||
// Brian Nickel (brian.nickel@gmail.com)
|
||||
//
|
||||
// Original Source:
|
||||
// apeitem.cpp from TagLib
|
||||
//
|
||||
// Copyright (C) 2005-2007 Brian Nickel
|
||||
// Copyright (C) 2004 by Allan Sandfeld Jensen (Original Implementation)
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License version
|
||||
// 2.1 as published by the Free Software Foundation.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
// USA
|
||||
//
|
||||
|
||||
using System;
|
||||
|
||||
namespace TagLib.Ape
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates the type of data stored in a <see cref="Item" />
|
||||
/// object.
|
||||
/// </summary>
|
||||
public enum ItemType
|
||||
{
|
||||
/// <summary>
|
||||
/// The item contains Unicode text.
|
||||
/// </summary>
|
||||
Text = 0,
|
||||
|
||||
/// <summary>
|
||||
/// The item contains binary data.
|
||||
/// </summary>
|
||||
Binary = 1,
|
||||
|
||||
/// <summary>
|
||||
/// The item contains a locator (file path/URL) for external
|
||||
/// information.
|
||||
/// </summary>
|
||||
Locator = 2
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This class provides a representation of an APEv2 tag item which
|
||||
/// can be read from and written to disk.
|
||||
/// </summary>
|
||||
public class Item : ICloneable
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Contains the item value.
|
||||
/// </summary>
|
||||
ReadOnlyByteVector data;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the item text.
|
||||
/// </summary>
|
||||
string[] text;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="Item" /> by reading in a raw APEv2 item.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object containing the item to
|
||||
/// read.
|
||||
/// </param>
|
||||
/// <param name="offset">
|
||||
/// A <see cref="int" /> value specifying the offset in
|
||||
/// <paramref name="data" /> at which the item data begins.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="data" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// <paramref name="offset" /> is less than zero.
|
||||
/// </exception>
|
||||
/// <exception cref="CorruptFileException">
|
||||
/// A complete item could not be read.
|
||||
/// </exception>
|
||||
public Item (ByteVector data, int offset)
|
||||
{
|
||||
if (data == null)
|
||||
throw new ArgumentNullException (nameof (data));
|
||||
|
||||
Parse (data, offset);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="Item" /> with a specified key and value.
|
||||
/// </summary>
|
||||
/// <param name="key">
|
||||
/// A <see cref="string" /> object containing the key to use
|
||||
/// for the current instance.
|
||||
/// </param>
|
||||
/// <param name="value">
|
||||
/// A <see cref="string" /> object containing the value to
|
||||
/// store in the new instance.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="key" /> or <paramref name="value" /> is
|
||||
/// <see langword="null" />.
|
||||
/// </exception>
|
||||
public Item (string key, string value)
|
||||
{
|
||||
if (key == null)
|
||||
throw new ArgumentNullException (nameof (key));
|
||||
|
||||
if (value == null)
|
||||
throw new ArgumentNullException (nameof (value));
|
||||
|
||||
Key = key;
|
||||
text = new [] { value };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="Item" /> with a specified key and collection of
|
||||
/// values.
|
||||
/// </summary>
|
||||
/// <param name="key">
|
||||
/// A <see cref="string" /> object containing the key to use
|
||||
/// for the current instance.
|
||||
/// </param>
|
||||
/// <param name="value">
|
||||
/// A <see cref="T:string[]" /> containing the values to store
|
||||
/// in the new instance.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="key" /> or <paramref name="value" /> is
|
||||
/// <see langword="null" />.
|
||||
/// </exception>
|
||||
public Item (string key, params string[] value)
|
||||
{
|
||||
if (key == null)
|
||||
throw new ArgumentNullException (nameof (key));
|
||||
|
||||
if (value == null)
|
||||
throw new ArgumentNullException (nameof (value));
|
||||
|
||||
Key = key;
|
||||
text = (string[])value.Clone ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="Item" /> with a specified key and collection of
|
||||
/// values.
|
||||
/// </summary>
|
||||
/// <param name="key">
|
||||
/// A <see cref="string" /> object containing the key to use
|
||||
/// for the current instance.
|
||||
/// </param>
|
||||
/// <param name="value">
|
||||
/// A <see cref="StringCollection" /> object containing the
|
||||
/// values to store in the new instance.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="key" /> or <paramref name="value" /> is
|
||||
/// <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <seealso cref="Item(string,string[])" />
|
||||
[Obsolete ("Use Item(string,string[])")]
|
||||
public Item (string key, StringCollection value)
|
||||
{
|
||||
if (key == null)
|
||||
throw new ArgumentNullException (nameof (key));
|
||||
|
||||
if (value == null)
|
||||
throw new ArgumentNullException (nameof (value));
|
||||
|
||||
Key = key;
|
||||
text = value.ToArray ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="Item" /> with a specified key and raw data.
|
||||
/// </summary>
|
||||
/// <param name="key">
|
||||
/// A <see cref="string" /> object containing the key to use
|
||||
/// for the current instance.
|
||||
/// </param>
|
||||
/// <param name="value">
|
||||
/// A <see cref="StringCollection" /> object containing the
|
||||
/// values to store in the new instance.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// This constructor automatically marks the new instance as
|
||||
/// <see cref="ItemType.Binary" />.
|
||||
/// </remarks>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="key" /> or <paramref name="value" /> is
|
||||
/// <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <seealso cref="Item(string,string[])" />
|
||||
public Item (string key, ByteVector value)
|
||||
{
|
||||
Key = key;
|
||||
Type = ItemType.Binary;
|
||||
|
||||
data = value as ReadOnlyByteVector;
|
||||
if (data == null)
|
||||
data = new ReadOnlyByteVector (value);
|
||||
}
|
||||
|
||||
Item (Item item)
|
||||
{
|
||||
Type = item.Type;
|
||||
Key = item.Key;
|
||||
|
||||
if (item.data != null)
|
||||
data = new ReadOnlyByteVector (item.data);
|
||||
|
||||
if (item.text != null)
|
||||
text = (string[])item.text.Clone ();
|
||||
|
||||
ReadOnly = item.ReadOnly;
|
||||
Size = item.Size;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets the key used to identify the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string" /> object containing the key used to
|
||||
/// identify the current instance.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// This value is used for specifying the contents of the
|
||||
/// item in a common and consistant fashion. For example,
|
||||
/// <c>"TITLE"</c> specifies that the item contains the title
|
||||
/// of the track.
|
||||
/// </remarks>
|
||||
public string Key { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the binary value stored in the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="ByteVector" /> object containing the binary
|
||||
/// value stored in the current instance, or <see
|
||||
/// langword="null" /> if the item contains text.
|
||||
/// </value>
|
||||
public ByteVector Value {
|
||||
get { return (Type == ItemType.Binary) ? data : null; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the size of the current instance as it last appeared
|
||||
/// on disk.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="int" /> value containing the size of the
|
||||
/// current instance as it last appeared on disk.
|
||||
/// </value>
|
||||
public int Size { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the type of value contained in the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="ItemType" /> value indicating the type of
|
||||
/// value contained in the current instance.
|
||||
/// </value>
|
||||
public ItemType Type { get; set; } = ItemType.Text;
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets whether or not the current instance is
|
||||
/// flagged as read-only on disk.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="bool" /> value indicating whether or not the
|
||||
/// current instance is flagged as read-only on disk.
|
||||
/// </value>
|
||||
public bool ReadOnly { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether or not the current instance is empty.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="bool" /> value indicating whether or not the
|
||||
/// current instance contains no value.
|
||||
/// </value>
|
||||
public bool IsEmpty {
|
||||
get {
|
||||
if (Type != ItemType.Binary)
|
||||
return text == null || text.Length == 0;
|
||||
else
|
||||
return data == null || data.IsEmpty;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Gets the contents of the current instance as a <see
|
||||
/// cref="string" />.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// <para>A <see cref="string" /> object containing the text
|
||||
/// stored in the current instance, or <see langword="null"
|
||||
/// /> if the item is empty of contains binary data.</para>
|
||||
/// <para>If the current instance contains multiple string
|
||||
/// values, they will be returned as a comma separated
|
||||
/// value.</para>
|
||||
/// </returns>
|
||||
public override string ToString ()
|
||||
{
|
||||
if (Type == ItemType.Binary || text == null)
|
||||
return null;
|
||||
|
||||
return string.Join (", ", text);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the contents of the current instance as a <see
|
||||
/// cref="string" /> array.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="T:string[]" /> containing the text stored in
|
||||
/// the current instance, or an empty array if the item
|
||||
/// contains binary data.
|
||||
/// </returns>
|
||||
public string[] ToStringArray ()
|
||||
{
|
||||
if (Type == ItemType.Binary || text == null)
|
||||
return new string[0];
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renders the current instance as an APEv2 item.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVector" /> object containing the
|
||||
/// rendered version of the current instance.
|
||||
/// </returns>
|
||||
public ByteVector Render ()
|
||||
{
|
||||
uint flags = (uint)((ReadOnly) ? 1 : 0) |
|
||||
((uint)Type << 1);
|
||||
|
||||
if (IsEmpty)
|
||||
return new ByteVector ();
|
||||
|
||||
ByteVector result = null;
|
||||
|
||||
if (Type == ItemType.Binary) {
|
||||
if (text == null && data != null)
|
||||
result = data;
|
||||
}
|
||||
|
||||
if (result == null && text != null) {
|
||||
result = new ByteVector ();
|
||||
|
||||
for (int i = 0; i < text.Length; i++) {
|
||||
if (i != 0)
|
||||
result.Add (0);
|
||||
|
||||
result.Add (ByteVector.FromString (text[i], StringType.UTF8));
|
||||
}
|
||||
}
|
||||
|
||||
// If no data is stored, don't write the item.
|
||||
if (result == null || result.Count == 0)
|
||||
return new ByteVector ();
|
||||
|
||||
var output = new ByteVector {
|
||||
ByteVector.FromUInt ((uint)result.Count,
|
||||
false),
|
||||
ByteVector.FromUInt (flags, false),
|
||||
ByteVector.FromString (Key, StringType.UTF8),
|
||||
0,
|
||||
result
|
||||
};
|
||||
|
||||
Size = output.Count;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
/// <summary>
|
||||
/// Populates the current instance by reading in a raw APEv2
|
||||
/// item.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object containing the item to
|
||||
/// read.
|
||||
/// </param>
|
||||
/// <param name="offset">
|
||||
/// A <see cref="int" /> value specifying the offset in
|
||||
/// <paramref name="data" /> at which the item data begins.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="data" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// <paramref name="offset" /> is less than zero.
|
||||
/// </exception>
|
||||
/// <exception cref="CorruptFileException">
|
||||
/// A complete item could not be read.
|
||||
/// </exception>
|
||||
protected void Parse (ByteVector data, int offset)
|
||||
{
|
||||
if (data == null)
|
||||
throw new ArgumentNullException (nameof (data));
|
||||
|
||||
if (offset < 0)
|
||||
throw new ArgumentOutOfRangeException (nameof (offset));
|
||||
|
||||
|
||||
// 11 bytes is the minimum size for an APE item
|
||||
if (data.Count < offset + 11)
|
||||
throw new CorruptFileException ("Not enough data for APE Item");
|
||||
|
||||
uint value_length = data.Mid (offset, 4).ToUInt (false);
|
||||
uint flags = data.Mid (offset + 4, 4).ToUInt (false);
|
||||
|
||||
ReadOnly = (flags & 1) == 1;
|
||||
Type = (ItemType)((flags >> 1) & 3);
|
||||
|
||||
int pos = data.Find (ByteVector.TextDelimiter (StringType.UTF8), offset + 8);
|
||||
|
||||
Key = data.ToString (StringType.UTF8, offset + 8, pos - offset - 8);
|
||||
|
||||
if (value_length > data.Count - pos - 1)
|
||||
throw new CorruptFileException ("Invalid data length.");
|
||||
|
||||
Size = pos + 1 + (int)value_length - offset;
|
||||
|
||||
if (Type == ItemType.Binary)
|
||||
this.data = new ReadOnlyByteVector (data.Mid (pos + 1, (int)value_length));
|
||||
else
|
||||
text = data.Mid (pos + 1, (int)value_length).ToStrings (StringType.UTF8, 0);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region ICloneable
|
||||
|
||||
/// <summary>
|
||||
/// Creates a deep copy of the current instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A new <see cref="Item"/> object identical to the current
|
||||
/// instance.
|
||||
/// </returns>
|
||||
public Item Clone ()
|
||||
{
|
||||
return new Item (this);
|
||||
}
|
||||
|
||||
object ICloneable.Clone ()
|
||||
{
|
||||
return Clone ();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ec6d7edea3a67467d8e074bff4ac65d7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,359 @@
|
||||
//
|
||||
// StreamHeader.cs: Provides support for reading Monkey's Audio APE stream
|
||||
// properties.
|
||||
//
|
||||
// Author:
|
||||
// Helmut Wahrmann
|
||||
//
|
||||
// Copyright (C) 2007 Helmut Wahrmann
|
||||
// Copyright (C) 2007 Brian Nickel
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License version
|
||||
// 2.1 as published by the Free Software Foundation.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
// USA
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
|
||||
namespace TagLib.Ape
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates the compression level used when encoding a Monkey's
|
||||
/// Audio APE file.
|
||||
/// </summary>
|
||||
public enum CompressionLevel
|
||||
{
|
||||
/// <summary>
|
||||
/// The audio is not compressed.
|
||||
/// </summary>
|
||||
None = 0,
|
||||
|
||||
/// <summary>
|
||||
/// The audio is mildly compressed.
|
||||
/// </summary>
|
||||
Fast = 1000,
|
||||
|
||||
/// <summary>
|
||||
/// The audio is compressed at a normal level.
|
||||
/// </summary>
|
||||
Normal = 2000,
|
||||
|
||||
/// <summary>
|
||||
/// The audio is highly compressed.
|
||||
/// </summary>
|
||||
High = 3000,
|
||||
|
||||
/// <summary>
|
||||
/// The audio is extremely highly compressed.
|
||||
/// </summary>
|
||||
ExtraHigh = 4000,
|
||||
|
||||
/// <summary>
|
||||
/// The audio is compressed to an insane level.
|
||||
/// </summary>
|
||||
Insane
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This struct implements <see cref="IAudioCodec" /> to provide
|
||||
/// support for reading Monkey's Audio APE stream properties.
|
||||
/// </summary>
|
||||
public struct StreamHeader : IAudioCodec, ILosslessAudioCodec
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Contains the APE version.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is stored in bytes (4,5) of the file and is
|
||||
/// 1000 times the actual version number, so 3810 indicates
|
||||
/// version 3.81.
|
||||
/// </remarks>
|
||||
readonly ushort version;
|
||||
|
||||
/*
|
||||
/// <summary>
|
||||
/// Contains the format flags.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is stored in bytes (53,54).
|
||||
/// </remarks>
|
||||
private ushort format_flags;
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// Contains the number of audio blocks in one frame.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is stored in bytes (55-58).
|
||||
/// </remarks>
|
||||
readonly uint blocks_per_frame;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the number of audio blocks in the final frame.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is stored in bytes (59-62).
|
||||
/// </remarks>
|
||||
readonly uint final_frame_blocks;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the total number of frames.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is stored in bytes (63-66).
|
||||
/// </remarks>
|
||||
readonly uint total_frames;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the number of bits per sample.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is stored in bytes (67,68) and is typically
|
||||
/// 16.
|
||||
/// </remarks>
|
||||
readonly ushort bits_per_sample;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the number of channels.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is stored in bytes (69,70) and is typically
|
||||
/// 1 or 2.
|
||||
/// </remarks>
|
||||
readonly ushort channels;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the sample rate.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is stored in bytes (71-74) and is typically
|
||||
/// 44100.
|
||||
/// </remarks>
|
||||
readonly uint sample_rate;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the length of the audio stream.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is provided by the constructor.
|
||||
/// </remarks>
|
||||
readonly long stream_length;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Static Fields
|
||||
|
||||
/// <summary>
|
||||
/// The size of a Monkey Audio header.
|
||||
/// </summary>
|
||||
public const uint Size = 76;
|
||||
|
||||
/// <summary>
|
||||
/// The identifier used to recognize a WavPack file.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// "MAC "
|
||||
/// </value>
|
||||
public static readonly ReadOnlyByteVector FileIdentifier = "MAC ";
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="StreamHeader" /> for a specified header block and
|
||||
/// stream length.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object containing the stream
|
||||
/// header data.
|
||||
/// </param>
|
||||
/// <param name="streamLength">
|
||||
/// A <see cref="long" /> value containing the length of the
|
||||
/// Monkey Audio stream in bytes.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="data" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <exception cref="CorruptFileException">
|
||||
/// <paramref name="data" /> does not begin with <see
|
||||
/// cref="FileIdentifier" /> or is less than <see cref="Size"
|
||||
/// /> bytes long.
|
||||
/// </exception>
|
||||
public StreamHeader (ByteVector data, long streamLength)
|
||||
{
|
||||
if (data == null)
|
||||
throw new ArgumentNullException (nameof (data));
|
||||
|
||||
if (!data.StartsWith (FileIdentifier))
|
||||
throw new CorruptFileException (
|
||||
"Data does not begin with identifier.");
|
||||
|
||||
if (data.Count < Size)
|
||||
throw new CorruptFileException (
|
||||
"Insufficient data in stream header");
|
||||
|
||||
stream_length = streamLength;
|
||||
version = data.Mid (4, 2).ToUShort (false);
|
||||
Compression = (CompressionLevel)data.Mid (52, 2)
|
||||
.ToUShort (false);
|
||||
// format_flags = data.Mid(54, 2).ToUShort(false);
|
||||
blocks_per_frame = data.Mid (56, 4).ToUInt (false);
|
||||
final_frame_blocks = data.Mid (60, 4).ToUInt (false);
|
||||
total_frames = data.Mid (64, 4).ToUInt (false);
|
||||
bits_per_sample = data.Mid (68, 2).ToUShort (false);
|
||||
channels = data.Mid (70, 2).ToUShort (false);
|
||||
sample_rate = data.Mid (72, 4).ToUInt (false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets the duration of the media represented by the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="TimeSpan" /> containing the duration of the
|
||||
/// media represented by the current instance.
|
||||
/// </value>
|
||||
public TimeSpan Duration {
|
||||
get {
|
||||
if (sample_rate <= 0 || total_frames <= 0)
|
||||
return TimeSpan.Zero;
|
||||
|
||||
return TimeSpan.FromSeconds (
|
||||
((total_frames - 1) *
|
||||
blocks_per_frame + final_frame_blocks) /
|
||||
(double)sample_rate);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the types of media represented by the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Always <see cref="MediaTypes.Audio" />.
|
||||
/// </value>
|
||||
public MediaTypes MediaTypes {
|
||||
get { return MediaTypes.Audio; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a text description of the media represented by the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string" /> object containing a description
|
||||
/// of the media represented by the current instance.
|
||||
/// </value>
|
||||
public string Description {
|
||||
get {
|
||||
return string.Format (
|
||||
CultureInfo.InvariantCulture, "Monkey's Audio APE Version {0:0.000}", Version);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the bitrate of the audio represented by the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="int" /> value containing a bitrate of the
|
||||
/// audio represented by the current instance.
|
||||
/// </value>
|
||||
public int AudioBitrate {
|
||||
get {
|
||||
TimeSpan d = Duration;
|
||||
if (d <= TimeSpan.Zero)
|
||||
return 0;
|
||||
|
||||
return (int)((stream_length * 8L) / d.TotalSeconds) / 1000;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sample rate of the audio represented by the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="int" /> value containing the sample rate of
|
||||
/// the audio represented by the current instance.
|
||||
/// </value>
|
||||
public int AudioSampleRate {
|
||||
get { return (int)sample_rate; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of channels in the audio represented by
|
||||
/// the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="int" /> value containing the number of
|
||||
/// channels in the audio represented by the current
|
||||
/// instance.
|
||||
/// </value>
|
||||
public int AudioChannels {
|
||||
get { return channels; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the APE version of the audio represented by the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="double" /> value containing the APE version
|
||||
/// of the audio represented by the current instance.
|
||||
/// </value>
|
||||
public double Version {
|
||||
get { return version / (double)1000; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of bits per sample in the audio
|
||||
/// represented by the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="int" /> value containing the number of bits
|
||||
/// per sample in the audio represented by the current
|
||||
/// instance.
|
||||
/// </value>
|
||||
public int BitsPerSample {
|
||||
get { return bits_per_sample; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the level of compression used when encoding the
|
||||
/// audio represented by the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="CompressionLevel" /> value indicating the
|
||||
/// level of compression used when encoding the audio
|
||||
/// represented by the current instance.
|
||||
/// </value>
|
||||
public CompressionLevel Compression { get; private set; }
|
||||
|
||||
#endregion
|
||||
}␍}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d8234dea7db8f83ed86cb702f3474bbe
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e937bf4e5ed85bb70b1660583e8eb5dc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in new issue
Block a user