1
0
mirror of https://github.com/SineVector241/VoiceCraft-MCBE_Proximity_Chat.git synced 2024-11-20 10:27:45 +00:00
VoiceCraft-MCBE_Proximity_Chat/ATL/AudioData/IO/TAK.cs
2024-07-13 11:16:08 +10:00

141 lines
4.6 KiB
C#

using ATL.Logging;
using System;
using System.IO;
using static ATL.AudioData.AudioDataManager;
using Commons;
using static ATL.ChannelsArrangements;
using System.Collections.Generic;
namespace ATL.AudioData.IO
{
/// <summary>
/// Class for Tom's lossless Audio Kompressor files manipulation (extension : .TAK)
/// </summary>
class TAK : IAudioDataIO
{
public static readonly byte[] TAK_ID = Utils.Latin1Encoding.GetBytes("tBaK");
// Private declarations
private uint bits;
private uint sampleRate;
// ---------- INFORMATIVE INTERFACE IMPLEMENTATIONS & MANDATORY OVERRIDES
public int SampleRate => (int)sampleRate;
public bool IsVBR => false;
public Format AudioFormat
{
get;
}
public int CodecFamily => AudioDataIOFactory.CF_LOSSLESS;
public string FileName { get; }
public double BitRate { get; private set; }
public int BitDepth => bits > 0 ? (int)bits : -1;
public double Duration { get; private set; }
public ChannelsArrangement ChannelsArrangement { get; private set; }
/// <inheritdoc/>
public List<MetaDataIOFactory.TagType> GetSupportedMetas()
{
return new List<MetaDataIOFactory.TagType> { MetaDataIOFactory.TagType.APE };
}
public long AudioDataOffset { get; set; }
public long AudioDataSize { get; set; }
// ---------- CONSTRUCTORS & INITIALIZERS
private void resetData()
{
Duration = 0;
BitRate = 0;
bits = 0;
sampleRate = 0;
AudioDataOffset = -1;
AudioDataSize = 0;
}
public TAK(string filePath, Format format)
{
this.FileName = filePath;
AudioFormat = format;
resetData();
}
// ---------- SUPPORT METHODS
public static bool IsValidHeader(byte[] data)
{
return StreamUtils.ArrBeginsWith(data, TAK_ID);
}
public bool Read(Stream source, SizeInfo sizeInfo, MetaDataIO.ReadTagParams readTagParams)
{
bool result = false;
bool doLoop = true;
byte[] buffer = new byte[4];
resetData();
source.Seek(sizeInfo.ID3v2Size, SeekOrigin.Begin);
source.Read(buffer, 0, 4);
if (IsValidHeader(buffer))
{
result = true;
AudioDataOffset = source.Position - 4;
AudioDataSize = sizeInfo.FileSize - sizeInfo.APESize - sizeInfo.ID3v1Size - AudioDataOffset;
do // Loop metadata
{
source.Read(buffer, 0, 4);
var readData32 = StreamUtils.DecodeUInt32(buffer);
var metaType = readData32 & 0x7F;
var metaSize = readData32 >> 8;
var position = source.Position;
if (0 == metaType) doLoop = false; // End of metadata
else if (0x01 == metaType) // Stream info
{
source.Read(buffer, 0, 2);
var readData16 = StreamUtils.DecodeUInt16(buffer);
source.Read(buffer, 0, 4);
readData32 = StreamUtils.DecodeUInt32(buffer);
source.Read(buffer, 0, 4);
uint restOfData = StreamUtils.DecodeUInt32(buffer);
var sampleCount = (readData16 >> 14) + (readData32 << 2) + ((restOfData & 0x00000080) << 34);
sampleRate = ((restOfData >> 4) & 0x03ffff) + 6000; // bits 5 to 22
bits = ((restOfData >> 22) & 0x1f) + 8; // bits 23 to 27
ChannelsArrangement = GuessFromChannelNumber((int)((restOfData >> 27) & 0x0f) + 1); // bits 28 to 31
if (sampleCount > 0)
{
Duration = (double)sampleCount * 1000.0 / sampleRate;
BitRate = Math.Round(((double)(sizeInfo.FileSize - source.Position)) * 8 / Duration); //time to calculate average bitrate
}
}
else if (0x04 == metaType) // Encoder info
{
source.Read(buffer, 0, 4);
readData32 = StreamUtils.DecodeUInt32(buffer);
}
source.Seek(position + metaSize, SeekOrigin.Begin);
} while (doLoop); // End of metadata loop
}
return result;
}
}
}