Initial commit

This commit is contained in:
Thastertyn committed 2024-06-07 00:47:07 +02:00
commit 262601edb8
2025 files changed
+218754

No files matched your search

+191
View File
@@ -0,0 +1,191 @@
//
// Block.cs: Represents a Flac metadata block.
//
// Author:
// Brian Nickel (brian.nickel@gmail.com)
//
// 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.Flac
{
/// <summary>
/// This class represents a Flac metadata block.
/// </summary>
public class Block
{
#region Private Fields
/// <summary>
/// Contains the block header.
/// </summary>
readonly BlockHeader header;
#endregion
#region Constructors
/// <summary>
/// Constructs and initializes a new instance of <see
/// cref="Block" /> with a specified header and internal
/// data.
/// </summary>
/// <param name="header">
/// A <see cref="BlockHeader" /> object containing the
/// header to use for the new instance.
/// </param>
/// <param name="data">
/// A <see cref="ByteVector" /> object containing the data
/// to be contained in the new instance.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="data" /> is <see langword="null" />.
/// </exception>
/// <exception cref="CorruptFileException">
/// The size of <paramref name="data" /> does not match the
/// size specified in <paramref name="header" />.
/// </exception>
public Block (BlockHeader header, ByteVector data)
{
if (data == null)
throw new ArgumentNullException (nameof (data));
if (header.BlockSize != data.Count)
throw new CorruptFileException ("Data count not equal to block size.");
this.header = header;
Data = data;
}
/// <summary>
/// Constructs and initializes a new instance of <see
/// cref="Block" /> with of a specified type and internal
/// data.
/// </summary>
/// <param name="type">
/// A <see cref="BlockType" /> value indicating the type of
/// data stored in <paramref name="data" />.
/// </param>
/// <param name="data">
/// A <see cref="ByteVector" /> object containing the data
/// to be contained in the new instance.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="data" /> is <see langword="null" />.
/// </exception>
public Block (BlockType type, ByteVector data)
{
if (data == null)
throw new ArgumentNullException (nameof (data));
header = new BlockHeader (type, (uint)data.Count);
Data = data;
}
#endregion
#region Public Properties
/// <summary>
/// Gets the type of data contained in the current instance.
/// </summary>
/// <value>
/// A <see cref="BlockType" /> value indicating the type of
/// data contained in <see cref="Data" />.
/// </value>
public BlockType Type {
get { return header.BlockType; }
}
/// <summary>
/// Gets whether or not the block represented by the current
/// instance is the last metadata block in the Flac stream.
/// </summary>
/// <value>
/// <see langword="true" /> if the block represented by the
/// current instance was the last one to appear in the file
/// and is followed immediately by the audio data, or <see
/// langword="false" /> if another block appears after the
/// current one or the block was not read from disk.
/// </value>
public bool IsLastBlock {
get { return header.IsLastBlock; }
}
/// <summary>
/// Gets the size of the data contained in the current
/// instance.
/// </summary>
public uint DataSize {
get { return header.BlockSize; }
}
/// <summary>
/// Gets the total size of the block represented by the
/// current instance as it appears on disk.
/// </summary>
public uint TotalSize {
get { return DataSize + BlockHeader.Size; }
}
/// <summary>
/// Gets the data contained in the current instance.
/// </summary>
/// <value>
/// A <see cref="ByteVector" /> object containing the data
/// stored in the current instance.
/// </value>
public ByteVector Data { get; private set; }
#endregion
#region Public Methods
/// <summary>
/// Renders the current instance as a raw Flac metadata
/// block.
/// </summary>
/// <param name="isLastBlock">
/// A <see cref="bool" /> value indicating whether or not the
/// block is to be marked as the last metadata block.
/// </param>
/// <returns>
/// A <see cref="ByteVector" /> object containing the
/// rendered version of the current instance.
/// </returns>
public ByteVector Render (bool isLastBlock)
{
if (Data == null)
throw new InvalidOperationException ("Cannot render empty blocks.");
ByteVector data = header.Render (isLastBlock);
data.Add (Data);
return data;
}
#endregion
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2b85066ddbb2e476dacfb9957cb823bc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+175
View File
@@ -0,0 +1,175 @@
//
// BlockHeader.cs:
//
// Author:
// Brian Nickel (brian.nickel@gmail.com)
//
// 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.Flac
{
/// <summary>
/// Specifies the contents of a Flac block in <see cref="BlockHeader"
/// />.
/// </summary>
public enum BlockType
{
/// <summary>
/// The block contains stream information.
/// </summary>
StreamInfo = 0,
/// <summary>
/// The block contains padding.
/// </summary>
Padding,
/// <summary>
/// The block contains application data.
/// </summary>
Application,
/// <summary>
/// The block contains seek table.
/// </summary>
SeekTable,
/// <summary>
/// The block contains a Xipp comment.
/// </summary>
XiphComment,
/// <summary>
/// The block contains a cue sheet.
/// </summary>
CueSheet,
/// <summary>
/// The block contains a picture.
/// </summary>
Picture
}
/// <summary>
/// This structure provides a representation of a Flac metadata block
/// header structure.
/// </summary>
public struct BlockHeader
{
/// <summary>
/// The size of a block header.
/// </summary>
public const uint Size = 4;
/// <summary>
/// Constructs and initializes a new instance of <see
/// cref="BlockHeader" /> by reading a raw header from a <see
/// cref="ByteVector" /> object.
/// </summary>
/// <param name="data">
/// A <see cref="ByteVector" /> object containing a raw
/// block header.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="data" /> is <see langword="null" />.
/// </exception>
/// <exception cref="CorruptFileException">
/// <paramref name="data" /> contains less than 4 bytes.
/// </exception>
public BlockHeader (ByteVector data)
{
if (data == null)
throw new ArgumentNullException (nameof (data));
if (data.Count < Size)
throw new CorruptFileException ("Not enough data in Flac header.");
BlockType = (BlockType)(data[0] & 0x7f);
IsLastBlock = (data[0] & 0x80) != 0;
BlockSize = data.Mid (1, 3).ToUInt ();
}
/// <summary>
/// Constructs and initializes a new instance of <see
/// cref="BlockHeader" /> for a specified block type and size.
/// </summary>
/// <param name="type">
/// A <see cref="BlockType" /> value describing the contents
/// of the block.
/// </param>
/// <param name="blockSize">
/// A <see cref="uint" /> value containing the block data
/// size minus the size of the header.
/// </param>
public BlockHeader (BlockType type, uint blockSize)
{
BlockType = type;
IsLastBlock = false;
BlockSize = blockSize;
}
/// <summary>
/// Renderes the current instance as a raw Flac block header.
/// </summary>
/// <param name="isLastBlock">
/// A <see cref="bool" /> value specifying whether or not the
/// header is the last header of the file.
/// </param>
/// <returns>
/// A <see cref="ByteVector" /> object containing the
/// rendered header.
/// </returns>
public ByteVector Render (bool isLastBlock)
{
ByteVector data = ByteVector.FromUInt (BlockSize);
data[0] = (byte)(BlockType + (isLastBlock ? 0x80 : 0));
return data;
}
/// <summary>
/// Gets the type of block described by the current instance.
/// </summary>
/// <value>
/// A <see cref="BlockType" /> value describing the block
/// type.
/// </value>
public BlockType BlockType { get; private set; }
/// <summary>
/// Gets whether or not the block is the last in the file.
/// </summary>
/// <value>
/// <see langword="true" /> if the block is the last in the
/// file; otherwise <see langword="false" />.
/// </value>
public bool IsLastBlock { get; private set; }
/// <summary>
/// Gets the size of the block described by the current
/// instance, minus the block header.
/// </summary>
/// <value>
/// A <see cref="uint" /> value containing the size of the
/// block, minus the header.
/// </value>
public uint BlockSize { get; private set; }
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bdff34f1d4c26490c97cebf8fd90d80d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+665
View File
@@ -0,0 +1,665 @@
//
// File.cs: Provides tagging and properties support for Xiph's Flac audio files.
//
// Author:
// Brian Nickel (brian.nickel@gmail.com)
//
// Original Source:
// flacfile.cpp from TagLib
//
// Copyright (C) 2006-2007 Brian Nickel
// Copyright (C) 2003-2004 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;
using System.Collections.Generic;
namespace TagLib.Flac
{
/// <summary>
/// This class extends <see cref="TagLib.NonContainer.File" /> to
/// provide tagging and properties support for Xiph's Flac audio
/// files.
/// </summary>
/// <remarks>
/// A <see cref="TagLib.Ogg.XiphComment" /> will be added
/// automatically to any file that doesn't contain one. This change
/// does not effect the physical file until <see cref="Save" /> is
/// called and can be reversed using the following method:
/// <code>file.RemoveTags (file.TagTypes &amp; ~file.TagTypesOnDisk);</code>
/// </remarks>
[SupportedMimeType ("taglib/flac", "flac")]
[SupportedMimeType ("audio/x-flac")]
[SupportedMimeType ("application/x-flac")]
[SupportedMimeType ("audio/flac")]
public class File : TagLib.NonContainer.File
{
#region Private Fields
/// <summary>
/// Contains the Flac metadata tag.
/// </summary>
Metadata metadata;
/// <summary>
/// Contains the combination of all file tags.
/// </summary>
CombinedTag tag;
/// <summary>
/// Contains the Flac header block.
/// </summary>
ByteVector header_block;
/// <summary>
/// Contains the stream start position.
/// </summary>
long stream_start;
#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 Properties
/// <summary>
/// Gets a abstract representation of all tags stored in the
/// current instance.
/// </summary>
/// <value>
/// A <see cref="TagLib.Tag" /> object representing all tags
/// stored in the current instance.
/// </value>
public override Tag Tag {
get { return tag; }
}
#endregion
#region Public Methods
/// <summary>
/// Saves the changes made in the current instance to the
/// file it represents.
/// </summary>
public override void Save ()
{
// Boilerplate
PreSave ();
Mode = AccessMode.Write;
try {
// Update the tags at the beginning of the file.
long metadata_start = StartTag.Write ();
// Get all the blocks, but don't read the data for ones
// we're filling with stored data.
IList<Block> old_blocks = ReadBlocks (ref metadata_start,
out var metadata_end, BlockMode.Blacklist,
BlockType.XiphComment, BlockType.Picture);
// Create new vorbis comments is they don't exist.
GetTag (TagTypes.Xiph, true);
// Create new blocks and add the basics.
var new_blocks = new List<Block> ();
new_blocks.Add (old_blocks[0]);
// Add blocks we don't deal with from the file.
foreach (Block block in old_blocks)
if (block.Type != BlockType.StreamInfo &&
block.Type != BlockType.XiphComment &&
block.Type != BlockType.Picture &&
block.Type != BlockType.Padding)
new_blocks.Add (block);
new_blocks.Add (new Block (BlockType.XiphComment,
(GetTag (TagTypes.Xiph, true) as Ogg.XiphComment).Render (false)));
foreach (IPicture picture in metadata.Pictures) {
if (picture == null)
continue;
new_blocks.Add (new Block (BlockType.Picture,
new Picture (picture).Render ()));
}
// Get the length of the blocks.
long length = 0;
foreach (Block block in new_blocks)
length += block.TotalSize;
// Find the padding size to avoid trouble. If that fails
// make some.
long padding_size = metadata_end - metadata_start -
BlockHeader.Size - length;
if (padding_size < 0)
padding_size = 1024 * 4;
// Add a padding block.
if (padding_size != 0)
new_blocks.Add (new Block (BlockType.Padding,
new ByteVector ((int)padding_size)));
// Render the blocks.
ByteVector block_data = new ByteVector ();
for (int i = 0; i < new_blocks.Count; i++)
block_data.Add (new_blocks[i].Render (
i == new_blocks.Count - 1));
// Update the blocks.
Insert (block_data, metadata_start, metadata_end -
metadata_start);
// Update the tags at the end of the file.
EndTag.Write ();
TagTypesOnDisk = TagTypes;
} finally {
Mode = AccessMode.Closed;
}
}
/// <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>
public override Tag GetTag (TagTypes type, bool create)
{
switch (type) {
case TagTypes.Xiph:
return metadata.GetComment (create, tag);
case TagTypes.FlacMetadata:
return metadata;
}
Tag t = (base.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;
}
}
/// <summary>
/// Removes a set of tag types from the current instance.
/// </summary>
/// <param name="types">
/// A bitwise combined <see cref="TagLib.TagTypes" /> value
/// containing tag types to be removed from the file.
/// </param>
/// <remarks>
/// In order to remove all tags from a file, pass <see
/// cref="TagTypes.AllTags" /> as <paramref name="types" />.
/// </remarks>
public override void RemoveTags (TagTypes types)
{
if ((types & TagTypes.Xiph) != 0)
metadata.RemoveComment ();
if ((types & TagTypes.FlacMetadata) != 0)
metadata.Clear ();
base.RemoveTags (types);
}
#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)
{
var blocks = ReadBlocks (ref start, out var end, BlockMode.Whitelist, BlockType.StreamInfo, BlockType.XiphComment, BlockType.Picture);
metadata = new Metadata (blocks);
TagTypesOnDisk |= metadata.TagTypes;
if ((propertiesStyle & ReadStyle.Average) != 0) {
// Check that the first block is a
// METADATA_BLOCK_STREAMINFO.
if (blocks.Count == 0 || blocks[0].Type != BlockType.StreamInfo)
throw new CorruptFileException ("FLAC stream does not begin with StreamInfo.");
// The stream exists from the end of the last
// block to the end of the file.
stream_start = end;
header_block = blocks[0].Data;
}
}
/// <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)
{
tag = new CombinedTag (metadata, base.Tag);
GetTag (TagTypes.Xiph, 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)
{
var header = new StreamHeader (header_block, end - stream_start);
return new Properties (TimeSpan.Zero, header);
}
#endregion
#region Private Methods
/// <summary>
/// Indicates whether or not the block types passed into
/// <see cref="ReadBlocks" /> are to be white-listed or
/// black-listed.
/// </summary>
enum BlockMode
{
/// <summary>
/// All block types except those provided are to be
/// returned.
/// </summary>
Blacklist,
/// <summary>
/// Only those block types provides should be
/// returned.
/// </summary>
Whitelist
}
/// <summary>
/// Reads all metadata blocks starting from the current
/// instance, starting at a specified position.
/// </summary>
/// <param name="start">
/// A <see cref="long" /> value reference specifying the
/// position at which to start searching for the blocks. This
/// will be updated to the position of the first block.
/// </param>
/// <param name="end">
/// A <see cref="long" /> value reference updated to the
/// position at which the last block ends.
/// </param>
/// <param name="mode">
/// A <see cref="BlockMode" /> value indicating whether to
/// white-list or black-list the contents of <paramref
/// name="types" />.
/// </param>
/// <param name="types">
/// A <see cref="T:BlockType[]" /> containing the types to look
/// for or not look for as specified by <paramref name="mode"
/// />.
/// </param>
/// <returns>
/// A <see cref="T:System.Collections.Generic.IList`1" /> object containing the blocks
/// read from the current instance.
/// </returns>
/// <exception cref="CorruptFileException">
/// "<c>fLaC</c>" could not be found.
/// </exception>
IList<Block> ReadBlocks (ref long start, out long end, BlockMode mode, params BlockType[] types)
{
List<Block> blocks = new List<Block> ();
long start_position = Find ("fLaC", start);
if (start_position < 0)
throw new CorruptFileException ("FLAC stream not found at starting position.");
end = start = start_position + 4;
Seek (start);
BlockHeader header;
do {
header = new BlockHeader (ReadBlock ((int)BlockHeader.Size));
bool found = false;
foreach (BlockType type in types)
if (header.BlockType == type) {
found = true;
break;
}
if ((mode == BlockMode.Whitelist && found) ||
(mode == BlockMode.Blacklist && !found))
blocks.Add (new Block (header, ReadBlock ((int)header.BlockSize)));
else
Seek (header.BlockSize, System.IO.SeekOrigin.Current);
end += header.BlockSize + BlockHeader.Size;
} while (!header.IsLastBlock);
return blocks;
}
#endregion
}
/// <summary>
/// This class extends <see cref="CombinedTag" /> to provide support
/// for reading and writing FLAC metadata boxes.
/// </summary>
/// <remarks>
/// At this point, only Xiph Comments and pictures are supported.
/// </remarks>
public class Metadata : CombinedTag
{
/// <summary>
/// Contains the pictures.
/// </summary>
readonly List<IPicture> pictures = new List<IPicture> ();
/// <summary>
/// Constructs and initializes a new instance of <see
/// cref="Metadata" /> using a collection of blocks.
/// </summary>
/// <param name="blocks">
/// A <see cref="T:System.Collections.Generic.List`1" /> object containing <see
/// cref="Block" /> objects to use in the new instance.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="blocks" /> is <see langword="null" />.
/// </exception>
[Obsolete ("Use Metadata(IEnumerable<Block>)")]
public Metadata (List<Block> blocks)
: this (blocks as IEnumerable<Block>)
{
}
/// <summary>
/// Constructs and initializes a new instance of <see
/// cref="Metadata" /> using a collection of blocks.
/// </summary>
/// <param name="blocks">
/// A <see cref="T:System.Collections.Generic.IEnumerable`1" /> object enumerating <see
/// cref="Block" /> objects to use in the new instance.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="blocks" /> is <see langword="null" />.
/// </exception>
public Metadata (IEnumerable<Block> blocks)
{
if (blocks == null)
throw new ArgumentNullException (nameof (blocks));
foreach (Block block in blocks) {
if (block.Data.Count == 0)
continue;
if (block.Type == BlockType.XiphComment)
AddTag (new Ogg.XiphComment (block.Data));
else if (block.Type == BlockType.Picture)
pictures.Add (new Picture (block.Data));
}
}
/// <summary>
/// Gets the first Xiph comment stored in the current
/// instance, optionally creating one if necessary.
/// </summary>
/// <param name="create">
/// A <see cref="bool" /> value indicating whether or not a
/// comment should be added if one cannot be found.
/// </param>
/// <param name="copy">
/// A <see cref="Tag" /> object containing the source tag to
/// copy the values from, or <see langword="null" /> to not
/// copy values.
/// </param>
/// <returns>
/// A <see cref="Ogg.XiphComment" /> 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>
public Ogg.XiphComment GetComment (bool create, Tag copy)
{
foreach (Tag t in Tags)
if (t is Ogg.XiphComment)
return t as Ogg.XiphComment;
if (!create)
return null;
Ogg.XiphComment c = new Ogg.XiphComment ();
if (copy != null)
copy.CopyTo (c, true);
AddTag (c);
return c;
}
/// <summary>
/// Removes all child Xiph Comments from the current
/// instance.
/// </summary>
public void RemoveComment ()
{
Ogg.XiphComment c;
while ((c = GetComment (false, null)) != null)
RemoveTag (c);
}
/// <summary>
/// Gets the tag types contained in the current instance.
/// </summary>
/// <value>
/// A bitwise combined <see cref="TagLib.TagTypes" /> value
/// containing the tag types stored in the current instance.
/// </value>
public override TagTypes TagTypes {
get { return TagTypes.FlacMetadata | base.TagTypes; }
}
/// <summary>
/// Gets and sets a collection of pictures associated with
/// the media represented by the current instance.
/// </summary>
/// <value>
/// A <see cref="T:IPicture[]" /> containing a collection of
/// pictures associated with the media represented by the
/// current instance or an empty array if none are present.
/// </value>
public override IPicture[] Pictures {
get { return pictures.ToArray (); }
set {
pictures.Clear ();
if (value != null)
pictures.AddRange (value);
}
}
/// <summary>
/// Clears the values stored in the current instance.
/// </summary>
public override void Clear ()
{
pictures.Clear ();
}
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2398030dd33fc28e38d41d1975d6aa92
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+268
View File
@@ -0,0 +1,268 @@
//
// Picture.cs:
//
// Author:
// Brian Nickel (brian.nickel@gmail.com)
//
// 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.Flac
{
/// <summary>
/// This class implements <see cref="IPicture" /> to provide support
/// for reading and writing Flac picture metadata.
/// </summary>
public class Picture : IPicture
{
#region Constructors
/// <summary>
/// Constructs and initializes a new instance of <see
/// cref="Picture" /> by reading the contents of a raw Flac
/// image structure.
/// </summary>
/// <param name="data">
/// A <see cref="ByteVector" /> object containing the raw
/// Flac image.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="data" /> is <see langword="null" />.
/// </exception>
/// <exception cref="CorruptFileException">
/// <paramref name="data" /> contains less than 32 bytes.
/// </exception>
public Picture (ByteVector data)
{
if (data == null)
throw new ArgumentNullException (nameof (data));
if (data.Count < 32)
throw new CorruptFileException ("Data must be at least 32 bytes long");
int pos = 0;
Type = (PictureType)data.Mid (pos, 4).ToUInt ();
pos += 4;
int mimetype_length = (int)data.Mid (pos, 4).ToUInt ();
pos += 4;
MimeType = data.ToString (StringType.Latin1, pos,
mimetype_length);
pos += mimetype_length;
int description_length = (int)data.Mid (pos, 4)
.ToUInt ();
pos += 4;
Description = data.ToString (StringType.UTF8, pos,
description_length);
pos += description_length;
Width = (int)data.Mid (pos, 4).ToUInt ();
pos += 4;
Height = (int)data.Mid (pos, 4).ToUInt ();
pos += 4;
ColorDepth = (int)data.Mid (pos, 4).ToUInt ();
pos += 4;
IndexedColors = (int)data.Mid (pos, 4).ToUInt ();
pos += 4;
int data_length = (int)data.Mid (pos, 4).ToUInt ();
pos += 4;
Data = data.Mid (pos, data_length);
}
/// <summary>
/// Constructs and initializes a new instance of <see
/// cref="Picture" /> by copying the properties of a <see
/// cref="IPicture" /> object.
/// </summary>
/// <param name="picture">
/// A <see cref="IPicture" /> object to use for the new
/// instance.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="picture" /> is <see langword="null" />.
/// </exception>
public Picture (IPicture picture)
{
if (picture == null)
throw new ArgumentNullException (nameof (picture));
Type = picture.Type;
MimeType = picture.MimeType;
Filename = picture.Filename;
Description = picture.Description;
Data = picture.Data;
if (!(picture is Picture flac_picture))
return;
Width = flac_picture.Width;
Height = flac_picture.Height;
ColorDepth = flac_picture.ColorDepth;
IndexedColors = flac_picture.IndexedColors;
}
#endregion
#region Public Methods
/// <summary>
/// Renders the current instance as a raw Flac picture.
/// </summary>
/// <returns>
/// A <see cref="ByteVector" /> object containing the
/// rendered version of the current instance.
/// </returns>
public ByteVector Render ()
{
var data = new ByteVector {
ByteVector.FromUInt ((uint)Type)
};
var mime_data = ByteVector.FromString (MimeType,
StringType.Latin1);
data.Add (ByteVector.FromUInt ((uint)mime_data.Count));
data.Add (mime_data);
var decription_data = ByteVector.FromString (Description, StringType.UTF8);
data.Add (ByteVector.FromUInt ((uint)decription_data.Count));
data.Add (decription_data);
data.Add (ByteVector.FromUInt ((uint)Width));
data.Add (ByteVector.FromUInt ((uint)Height));
data.Add (ByteVector.FromUInt ((uint)ColorDepth));
data.Add (ByteVector.FromUInt ((uint)IndexedColors));
data.Add (ByteVector.FromUInt ((uint)Data.Count));
data.Add (Data);
return data;
}
#endregion
#region Public Properties
/// <summary>
/// Gets and sets the mime-type of the picture data
/// stored in the current instance.
/// </summary>
/// <value>
/// A <see cref="string" /> object containing the mime-type
/// of the picture data stored in the current instance.
/// </value>
public string MimeType { get; set; }
/// <summary>
/// Gets and sets the type of content visible in the picture
/// stored in the current instance.
/// </summary>
/// <value>
/// A <see cref="PictureType" /> containing the type of
/// content visible in the picture stored in the current
/// instance.
/// </value>
public PictureType Type { get; set; }
/// <summary>
/// Gets and sets a filename of the picture stored in the
/// current instance.
/// </summary>
/// <value>
/// A <see cref="string" /> object containing a fielname, with
/// extension, of the picture stored in the current instance.
/// </value>
public string Filename { get; set; }
/// <summary>
/// Gets and sets a description of the picture stored in the
/// current instance.
/// </summary>
/// <value>
/// A <see cref="string" /> object containing a description
/// of the picture stored in the current instance.
/// </value>
public string Description { get; set; }
/// <summary>
/// Gets and sets the picture data stored in the current
/// instance.
/// </summary>
/// <value>
/// A <see cref="ByteVector" /> object containing the picture
/// data stored in the current instance.
/// </value>
public ByteVector Data { get; set; }
/// <summary>
/// Gets and sets the width of the picture in the current
/// instance.
/// </summary>
/// <value>
/// A <see cref="int" /> value containing width of the
/// picture stored in the current instance.
/// </value>
public int Width { get; set; }
/// <summary>
/// Gets and sets the height of the picture in the current
/// instance.
/// </summary>
/// <value>
/// A <see cref="int" /> value containing height of the
/// picture stored in the current instance.
/// </value>
public int Height { get; set; }
/// <summary>
/// Gets and sets the color depth of the picture in the
/// current instance.
/// </summary>
/// <value>
/// A <see cref="int" /> value containing color depth of the
/// picture stored in the current instance.
/// </value>
public int ColorDepth { get; set; }
/// <summary>
/// Gets and sets the number of indexed colors in the picture
/// in the current instance.
/// </summary>
/// <value>
/// A <see cref="int" /> value containing number of indexed
/// colors in the picture, or zero if the picture is not
/// stored in an indexed format.
/// </value>
public int IndexedColors { get; set; }
#endregion
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 948078d7fd9adb2fe995d19ef3157a39
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+234
View File
@@ -0,0 +1,234 @@
//
// StreamHeader.cs:
//
// Author:
// Brian Nickel (brian.nickel@gmail.com)
//
// Original Source:
// flagproperties.cpp from TagLib
//
// Copyright (C) 2006-2007 Brian Nickel
// Copyright (C) 2003 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.Flac
{
/// <summary>
/// This structure implements <see cref="IAudioCodec" /> and provides
/// information about a Flac audio stream.
/// </summary>
public struct StreamHeader : IAudioCodec, ILosslessAudioCodec
{
#region Private Properties
/// <summary>
/// Contains the flags.
/// </summary>
readonly uint flags;
/// <summary>
/// Contains the low portion of the length.
/// </summary>
readonly uint low_length;
/// <summary>
/// Contains the stream length.
/// </summary>
readonly long stream_length;
#endregion
#region Constructors
/// <summary>
/// Constructs and initializes a new instance of <see
/// cref="StreamHeader" /> by reading a raw stream header
/// structure and using the stream length.
/// </summary>
/// <param name="data">
/// A <see cref="ByteVector" /> object containing the raw
/// stream header.
/// </param>
/// <param name="streamLength">
/// A <see cref="long" /> value containing the length of the
/// stream.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="data" /> is <see langword="null" />.
/// </exception>
/// <exception cref="CorruptFileException">
/// <paramref name="data" /> contains less than 18 bytes.
/// </exception>
public StreamHeader (ByteVector data, long streamLength)
{
if (data == null)
throw new ArgumentNullException (nameof (data));
if (data.Count < 18)
throw new CorruptFileException ("Not enough data in FLAC header.");
stream_length = streamLength;
flags = data.Mid (10, 4).ToUInt (true);
low_length = data.Mid (14, 4).ToUInt (true);
}
#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 {
return (AudioSampleRate > 0 && stream_length > 0)
? TimeSpan.FromSeconds (
low_length /
(double)AudioSampleRate +
HighLength) :
TimeSpan.Zero;
}
}
/// <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 {
return (int)(Duration > TimeSpan.Zero ?
((stream_length * 8L) / Duration.TotalSeconds) / 1000 : 0);
}
}
/// <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)(flags >> 12); }
}
/// <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 (int)(((flags >> 9) & 7) + 1); }
}
/// <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 the sample width of the audio represented by the
/// current instance.
/// </summary>
/// <value>
/// A <see cref="int" /> value containing the sample width of
/// the audio represented by the current instance.
/// </value>
[Obsolete ("This property is depreciated, use BitsPerSample instead")]
public int AudioSampleWidth {
get { return BitsPerSample; }
}
/// <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 (int)(((flags >> 4) & 31) + 1); }
}
/// <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 "Flac Audio"; }
}
#endregion
#region Private Properties
/// <summary>
/// Gets a high portion of the length of the audio
/// represented by the current instance.
/// </summary>
/// <value>
/// A <see cref="uint" /> value containing the high portion
/// of the length.
/// </value>
uint HighLength {
get {
// The last 4 bits are the most significant 4
// bits for the 36 bit stream length in samples.
// (Audio files measured in days)
return (uint)(AudioSampleRate > 0 ?
(((flags & 0xf) << 28) /
AudioSampleRate) << 4 : 0);
}
}
#endregion
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 246c726d80e7bc9c68f191ac3d18e936
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: