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/OptimFROG.cs
2024-07-13 11:16:08 +10:00

206 lines
6.0 KiB
C#

using Commons;
using System;
using System.Collections.Generic;
using System.IO;
using static ATL.AudioData.AudioDataManager;
using static ATL.ChannelsArrangements;
namespace ATL.AudioData.IO
{
/// <summary>
/// Class for OptimFROG files manipulation (extensions : .OFR, .OFS)
/// </summary>
class OptimFrog : IAudioDataIO
{
private static readonly byte[] OFR_SIGNATURE = Utils.Latin1Encoding.GetBytes("OFR ");
#pragma warning disable S1144 // Unused private types or members should be removed
private static readonly string[] OFR_COMPRESSION = new string[10]
{
"fast", "normal", "high", "extra",
"best", "ultra", "insane", "highnew", "extranew", "bestnew"
};
private static readonly sbyte[] OFR_BITS = new sbyte[11]
{
8, 8, 16, 16, 24, 24, 32, 32,
-32, -32, -32 //negative value corresponds to floating point type.
};
#pragma warning restore S1144 // Unused private types or members should be removed
// Real structure of OptimFROG header
public class TOfrHeader
{
public byte[] ID = new byte[4]; // Always 'OFR '
public uint Size;
public uint Length;
public ushort HiLength;
public byte SampleType;
public byte ChannelMode;
public int SampleRate;
public ushort EncoderID;
public byte CompressionID;
public void Reset()
{
Array.Clear(ID, 0, ID.Length);
Size = 0;
Length = 0;
HiLength = 0;
SampleType = 0;
ChannelMode = 0;
SampleRate = 0;
EncoderID = 0;
CompressionID = 0;
}
}
private readonly TOfrHeader header = new TOfrHeader();
private SizeInfo sizeInfo;
// ---------- INFORMATIVE INTERFACE IMPLEMENTATIONS & MANDATORY OVERRIDES
/// <inheritdoc/>
public int SampleRate => getSampleRate();
/// <inheritdoc/>
public bool IsVBR => false;
/// <inheritdoc/>
public Format AudioFormat
{
get;
}
/// <inheritdoc/>
public int CodecFamily => AudioDataIOFactory.CF_LOSSLESS;
/// <inheritdoc/>
public string FileName { get; }
/// <inheritdoc/>
public double BitRate { get; private set; }
/// <inheritdoc/>
public int BitDepth => getBits();
/// <inheritdoc/>
public double Duration { get; private set; }
/// <inheritdoc/>
public ChannelsArrangement ChannelsArrangement => GuessFromChannelNumber(header.ChannelMode + 1);
/// <inheritdoc/>
public long AudioDataOffset { get; set; }
/// <inheritdoc/>
public long AudioDataSize { get; set; }
// ---------- CONSTRUCTORS & INITIALIZERS
private void resetData()
{
Duration = 0;
BitRate = 0;
AudioDataOffset = -1;
AudioDataSize = 0;
header.Reset();
}
public OptimFrog(string filePath, Format format)
{
this.FileName = filePath;
AudioFormat = format;
resetData();
}
// ---------- SUPPORT METHODS
// Get number of samples
private long getSamples()
{
return (header.Length >> header.ChannelMode) * 0x00000001 +
(header.HiLength >> header.ChannelMode) * 0x00010000;
}
// Get song duration
private double getDuration()
{
if (header.SampleRate > 0) return getSamples() * 1000.0 / header.SampleRate;
return 0;
}
private int getSampleRate()
{
return header.SampleRate;
}
private double getBitrate()
{
return (sizeInfo.FileSize - header.Size - sizeInfo.TotalTagSize) * 8 / Duration;
}
private sbyte getBits()
{
return OFR_BITS[header.SampleType];
}
public static bool IsValidHeader(byte[] data)
{
return StreamUtils.ArrBeginsWith(data, OFR_SIGNATURE);
}
public List<MetaDataIOFactory.TagType> GetSupportedMetas()
{
return new List<MetaDataIOFactory.TagType> { MetaDataIOFactory.TagType.APE, MetaDataIOFactory.TagType.ID3V2, MetaDataIOFactory.TagType.ID3V1 };
}
public bool Read(Stream source, SizeInfo sizeInfo, MetaDataIO.ReadTagParams readTagParams)
{
bool result = false;
this.sizeInfo = sizeInfo;
resetData();
// Read header data
source.Seek(sizeInfo.ID3v2Size, SeekOrigin.Begin);
long initialPos = source.Position;
byte[] buffer = new byte[4];
source.Read(header.ID, 0, 4);
source.Read(buffer, 0, 4);
header.Size = StreamUtils.DecodeUInt32(buffer);
source.Read(buffer, 0, 4);
header.Length = StreamUtils.DecodeUInt32(buffer);
source.Read(buffer, 0, 2);
header.HiLength = StreamUtils.DecodeUInt16(buffer);
source.Read(buffer, 0, 2);
header.SampleType = buffer[0];
header.ChannelMode = buffer[1];
source.Read(buffer, 0, 4);
header.SampleRate = StreamUtils.DecodeInt32(buffer);
source.Read(buffer, 0, 2);
header.EncoderID = StreamUtils.DecodeUInt16(buffer);
source.Read(buffer, 0, 1);
header.CompressionID = buffer[0];
if (IsValidHeader(header.ID))
{
result = true;
AudioDataOffset = initialPos;
AudioDataSize = sizeInfo.FileSize - sizeInfo.APESize - sizeInfo.ID3v1Size - AudioDataOffset;
Duration = getDuration();
BitRate = getBitrate();
}
return result;
}
}
}