Imported more DataFormats from original ExtensibleDataStorage codebase
This commit is contained in:
parent
d87b7580de
commit
2e89b9e13c
@ -0,0 +1,55 @@
|
||||
//
|
||||
// INTXLINKDataFormat.cs
|
||||
//
|
||||
// Author:
|
||||
// Mike Becker <alcexhim@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2019 Mike Becker
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
using System;
|
||||
using UniversalEditor.IO;
|
||||
using UniversalEditor.ObjectModels.Shortcut;
|
||||
|
||||
namespace UniversalEditor.DataFormats.Shortcut.Linux
|
||||
{
|
||||
public class LinuxShortcutDataFormat : DataFormat
|
||||
{
|
||||
protected override void LoadInternal(ref ObjectModel objectModel)
|
||||
{
|
||||
ShortcutObjectModel shortcut = (objectModel as ShortcutObjectModel);
|
||||
if (shortcut == null)
|
||||
throw new ObjectModelNotSupportedException();
|
||||
|
||||
Reader br = base.Accessor.Reader;
|
||||
string INTXLNK = br.ReadFixedLengthString(7);
|
||||
if (INTXLNK != "INTXLNK")
|
||||
throw new InvalidDataFormatException();
|
||||
|
||||
byte b = br.ReadByte();
|
||||
shortcut.ExecutableFileName = br.ReadStringToEnd(Encoding.UTF16LittleEndian);
|
||||
}
|
||||
protected override void SaveInternal(ObjectModel objectModel)
|
||||
{
|
||||
ShortcutObjectModel shortcut = (objectModel as ShortcutObjectModel);
|
||||
if (shortcut == null)
|
||||
throw new ObjectModelNotSupportedException();
|
||||
|
||||
Writer bw = base.Accessor.Writer;
|
||||
bw.WriteFixedLengthString("INTXLNK");
|
||||
bw.WriteByte(1);
|
||||
bw.WriteFixedLengthString(shortcut.ExecutableFileName, Encoding.UTF16LittleEndian);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -179,6 +179,7 @@
|
||||
<Compile Include="ObjectModels\JSON\Fields\JSONObjectField.cs" />
|
||||
<Compile Include="ObjectModels\JSON\Fields\JSONStringField.cs" />
|
||||
<Compile Include="DataFormats\Text\Plain\PlainTextDataFormat.cs" />
|
||||
<Compile Include="DataFormats\Shortcut\Linux\LinuxShortcutDataFormat.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\UniversalEditor.Core\UniversalEditor.Core.csproj">
|
||||
@ -199,6 +200,7 @@
|
||||
<Folder Include="ObjectModels\JSON\" />
|
||||
<Folder Include="ObjectModels\JSON\Fields\" />
|
||||
<Folder Include="DataFormats\Text\Plain\" />
|
||||
<Folder Include="DataFormats\Shortcut\Linux\" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
|
||||
@ -0,0 +1,96 @@
|
||||
//
|
||||
// HADataFormat.cs
|
||||
//
|
||||
// Author:
|
||||
// Mike Becker <alcexhim@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2019 Mike Becker
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
using System;
|
||||
using UniversalEditor.IO;
|
||||
using UniversalEditor.ObjectModels.FileSystem;
|
||||
|
||||
namespace UniversalEditor.DataFormats.FileSystem.HA
|
||||
{
|
||||
public class HADataFormat : DataFormat
|
||||
{
|
||||
public Compression.CompressionMethod CompressionMethod { get; set; } = Compression.CompressionMethod.None;
|
||||
|
||||
protected override DataFormatReference MakeReferenceInternal()
|
||||
{
|
||||
return base.MakeReferenceInternal();
|
||||
}
|
||||
protected override void LoadInternal(ref ObjectModel objectModel)
|
||||
{
|
||||
FileSystemObjectModel fsom = (objectModel as FileSystemObjectModel);
|
||||
if (fsom == null)
|
||||
throw new ObjectModelNotSupportedException();
|
||||
|
||||
Reader br = base.Accessor.Reader;
|
||||
string HA = br.ReadFixedLengthString(2);
|
||||
short cnt = br.ReadInt16();
|
||||
for (short c = 0; c < cnt; c++)
|
||||
{
|
||||
byte versionAndType = br.ReadByte();
|
||||
int compressedSize = br.ReadInt32();
|
||||
int decompressedSize = br.ReadInt32();
|
||||
int crc = br.ReadInt32();
|
||||
int fileTime = br.ReadInt32();
|
||||
string path = br.ReadNullTerminatedString();
|
||||
string name = br.ReadNullTerminatedString();
|
||||
string fileName = path + System.IO.Path.DirectorySeparatorChar.ToString() + name;
|
||||
byte machineSpecificInformationLength = br.ReadByte();
|
||||
for (byte b = 0; b < machineSpecificInformationLength; b = (byte)(b + 1))
|
||||
{
|
||||
byte machineSpecificInformationType = br.ReadByte();
|
||||
byte machineSpecificInformation = br.ReadByte();
|
||||
}
|
||||
|
||||
File f = fsom.AddFile(fileName);
|
||||
}
|
||||
}
|
||||
protected override void SaveInternal(ObjectModel objectModel)
|
||||
{
|
||||
FileSystemObjectModel fsom = (objectModel as FileSystemObjectModel);
|
||||
if (fsom == null)
|
||||
throw new ObjectModelNotSupportedException();
|
||||
|
||||
Writer bw = base.Accessor.Writer;
|
||||
bw.WriteFixedLengthString("HA");
|
||||
|
||||
File[] files = fsom.GetAllFiles();
|
||||
bw.WriteInt16((short)files.Length);
|
||||
foreach (File f in files)
|
||||
{
|
||||
byte versionAndType = 0;
|
||||
bw.WriteByte(versionAndType);
|
||||
byte[] decompressedData = f.GetData();
|
||||
byte[] compressedData = Compression.CompressionModule.FromKnownCompressionMethod(CompressionMethod).Compress(decompressedData);
|
||||
bw.WriteInt32(compressedData.Length);
|
||||
bw.WriteInt32(decompressedData.Length);
|
||||
int crc = 0;
|
||||
bw.WriteInt32(crc);
|
||||
int filetime = 0;
|
||||
bw.WriteInt32(filetime);
|
||||
string path = System.IO.Path.GetDirectoryName(f.Name);
|
||||
string name = System.IO.Path.GetFileName(f.Name);
|
||||
bw.WriteNullTerminatedString(path);
|
||||
bw.WriteNullTerminatedString(name);
|
||||
byte machineSpecificInformationLength = 0;
|
||||
bw.WriteByte(machineSpecificInformationLength);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,210 @@
|
||||
//
|
||||
// HyperArchiverDataFormat.cs
|
||||
//
|
||||
// Author:
|
||||
// Mike Becker <alcexhim@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2019 Mike Becker
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
using System;
|
||||
using UniversalEditor.IO;
|
||||
using UniversalEditor.ObjectModels.FileSystem;
|
||||
using UniversalEditor.ObjectModels.FileSystem.FileSources;
|
||||
|
||||
namespace UniversalEditor.DataFormats.FileSystem.HyperArchiver
|
||||
{
|
||||
public class HyperArchiverDataFormat : DataFormat
|
||||
{
|
||||
protected override void LoadInternal(ref ObjectModel objectModel)
|
||||
{
|
||||
FileSystemObjectModel fsom = (objectModel as FileSystemObjectModel);
|
||||
if (fsom == null)
|
||||
throw new ObjectModelNotSupportedException();
|
||||
|
||||
Reader br = base.Accessor.Reader;
|
||||
if (br.ReadByte() != 0x1a)
|
||||
throw new InvalidDataFormatException();
|
||||
|
||||
while (!br.EndOfStream)
|
||||
{
|
||||
Compression.CompressionMethod CompressionMethod = Compression.CompressionMethod.None;
|
||||
switch (br.ReadFixedLengthString(2))
|
||||
{
|
||||
case "HP":
|
||||
{
|
||||
CompressionMethod = Compression.CompressionMethod.LZW;
|
||||
break;
|
||||
}
|
||||
case "ST":
|
||||
{
|
||||
CompressionMethod = Compression.CompressionMethod.None;
|
||||
break;
|
||||
}
|
||||
case "BZ":
|
||||
{
|
||||
CompressionMethod = Compression.CompressionMethod.Bzip2;
|
||||
break;
|
||||
}
|
||||
case "DE":
|
||||
{
|
||||
CompressionMethod = Compression.CompressionMethod.Deflate;
|
||||
break;
|
||||
}
|
||||
case "DZ":
|
||||
{
|
||||
CompressionMethod = Compression.CompressionMethod.Deflate64;
|
||||
break;
|
||||
}
|
||||
case "GZ":
|
||||
{
|
||||
CompressionMethod = Compression.CompressionMethod.Gzip;
|
||||
break;
|
||||
}
|
||||
case "MA":
|
||||
{
|
||||
CompressionMethod = Compression.CompressionMethod.LZMA;
|
||||
break;
|
||||
}
|
||||
case "ZS":
|
||||
{
|
||||
CompressionMethod = Compression.CompressionMethod.LZSS;
|
||||
break;
|
||||
}
|
||||
case "PP":
|
||||
{
|
||||
CompressionMethod = Compression.CompressionMethod.PPPMd;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
byte version = br.ReadByte();
|
||||
int compressedFileSize = br.ReadInt32();
|
||||
uint decompressedFileSize = br.ReadUInt32();
|
||||
int dateTimeMSDOS = br.ReadInt32();
|
||||
int crc32 = br.ReadInt32();
|
||||
byte fileAttribute = br.ReadByte();
|
||||
byte fileNameLength = br.ReadByte();
|
||||
string fileName = br.ReadFixedLengthString(fileNameLength);
|
||||
|
||||
File f = fsom.AddFile(fileName);
|
||||
f.DataRequest += F_DataRequest;
|
||||
f.Properties.Add("reader", br);
|
||||
f.Properties.Add("offset", base.Accessor.Position);
|
||||
f.Properties.Add("method", CompressionMethod);
|
||||
f.Properties.Add("compressedLength", compressedFileSize);
|
||||
f.Properties.Add("decompressedLength", decompressedFileSize);
|
||||
|
||||
br.Seek(compressedFileSize, SeekOrigin.Current);
|
||||
}
|
||||
}
|
||||
|
||||
void F_DataRequest(object sender, DataRequestEventArgs e)
|
||||
{
|
||||
File f = (sender as File);
|
||||
Reader br = (Reader)f.Properties["reader"];
|
||||
Compression.CompressionMethod CompressionMethod = (Compression.CompressionMethod)f.Properties["method"];
|
||||
int compressedLength = (int)f.Properties["compressedLength"];
|
||||
uint decompressedLength = (uint)f.Properties["decompressedLength"];
|
||||
byte[] compressedData = br.ReadBytes(compressedLength);
|
||||
byte[] decompressedData = Compression.CompressionModule.FromKnownCompressionMethod(CompressionMethod).Decompress(compressedData); //, decompressedLength);
|
||||
e.Data = decompressedData;
|
||||
}
|
||||
|
||||
public byte Version { get; set; } = 0;
|
||||
|
||||
|
||||
protected override void SaveInternal(ObjectModel objectModel)
|
||||
{
|
||||
FileSystemObjectModel fsom = (objectModel as FileSystemObjectModel);
|
||||
if (fsom == null)
|
||||
throw new ObjectModelNotSupportedException();
|
||||
|
||||
Writer bw = base.Accessor.Writer;
|
||||
bw.WriteByte(0x1a);
|
||||
|
||||
File[] files = fsom.GetAllFiles();
|
||||
for (int i = 0; i < files.Length; i++)
|
||||
{
|
||||
Compression.CompressionMethod compressionMethod = Compression.CompressionMethod.None; // files[i].CompressionMethod;
|
||||
switch (compressionMethod)
|
||||
{
|
||||
case Compression.CompressionMethod.Deflate:
|
||||
{
|
||||
bw.WriteFixedLengthString("DE");
|
||||
break;
|
||||
}
|
||||
case Compression.CompressionMethod.Deflate64:
|
||||
{
|
||||
bw.WriteFixedLengthString("DZ");
|
||||
break;
|
||||
}
|
||||
case Compression.CompressionMethod.Bzip2:
|
||||
{
|
||||
bw.WriteFixedLengthString("BZ");
|
||||
break;
|
||||
}
|
||||
case Compression.CompressionMethod.LZMA:
|
||||
{
|
||||
bw.WriteFixedLengthString("MA");
|
||||
break;
|
||||
}
|
||||
case Compression.CompressionMethod.LZW:
|
||||
{
|
||||
bw.WriteFixedLengthString("HP");
|
||||
break;
|
||||
}
|
||||
case Compression.CompressionMethod.LZSS:
|
||||
{
|
||||
bw.WriteFixedLengthString("ZS");
|
||||
break;
|
||||
}
|
||||
case Compression.CompressionMethod.PPPMd:
|
||||
{
|
||||
bw.WriteFixedLengthString("PP");
|
||||
break;
|
||||
}
|
||||
case Compression.CompressionMethod.Gzip:
|
||||
{
|
||||
bw.WriteFixedLengthString("GZ");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
bw.WriteFixedLengthString("ST");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bw.WriteByte(Version);
|
||||
byte[] decompressedData = files[i].GetData();
|
||||
byte[] compressedData = Compression.CompressionModule.FromKnownCompressionMethod(compressionMethod).Compress(decompressedData);
|
||||
int compressedFileSize = compressedData.Length;
|
||||
uint decompressedFileSize = (uint)decompressedData.Length;
|
||||
bw.WriteInt32(compressedFileSize);
|
||||
bw.WriteUInt32(decompressedFileSize);
|
||||
int dateTimeMSDOS = 0;
|
||||
bw.WriteInt32(dateTimeMSDOS);
|
||||
int crc32 = 0;
|
||||
bw.WriteInt32(crc32);
|
||||
byte fileAttribute = 0;
|
||||
bw.WriteByte(fileAttribute);
|
||||
byte fileNameLength = (byte)files[i].Name.Length;
|
||||
bw.WriteByte(fileNameLength);
|
||||
bw.WriteFixedLengthString(files[i].Name, fileNameLength);
|
||||
bw.WriteBytes(compressedData);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -228,6 +228,8 @@
|
||||
<Compile Include="DataFormats\FileSystem\VMware\VMDKAdapterType.cs" />
|
||||
<Compile Include="DataFormats\FileSystem\VMware\VMDKCreateType.cs" />
|
||||
<Compile Include="DataFormats\FileSystem\VMware\VMDKDiskGeometry.cs" />
|
||||
<Compile Include="DataFormats\FileSystem\HA\HADataFormat.cs" />
|
||||
<Compile Include="DataFormats\FileSystem\HyperArchiver\HyperArchiverDataFormat.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Libraries\UniversalEditor.Core\UniversalEditor.Core.csproj">
|
||||
@ -263,6 +265,8 @@
|
||||
<Folder Include="DataFormats\FileSystem\SquareSoft\" />
|
||||
<Folder Include="DataFormats\FileSystem\RealNetworks\" />
|
||||
<Folder Include="DataFormats\FileSystem\VMware\" />
|
||||
<Folder Include="DataFormats\FileSystem\HA\" />
|
||||
<Folder Include="DataFormats\FileSystem\HyperArchiver\" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
|
||||
@ -0,0 +1,29 @@
|
||||
//
|
||||
// AdlibBlockType.cs
|
||||
//
|
||||
// Author:
|
||||
// Mike Becker <alcexhim@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2019 Mike Becker
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
using System;
|
||||
namespace UniversalEditor.DataFormats.Multimedia.Audio.Synthesized.EdLib
|
||||
{
|
||||
public enum AdlibBlockType
|
||||
{
|
||||
Unknown = -1,
|
||||
MusicData = 0
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
//
|
||||
// AdlibSoundcard.cs
|
||||
//
|
||||
// Author:
|
||||
// Mike Becker <alcexhim@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2019 Mike Becker
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
using System;
|
||||
namespace UniversalEditor.DataFormats.Multimedia.Audio.Synthesized.EdLib
|
||||
{
|
||||
public enum AdlibSoundcard
|
||||
{
|
||||
Unknown = -1,
|
||||
Adlib = 0
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,155 @@
|
||||
//
|
||||
// D00DataFormat.cs
|
||||
//
|
||||
// Author:
|
||||
// Mike Becker <alcexhim@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2019 Mike Becker
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
using System;
|
||||
using UniversalEditor.IO;
|
||||
|
||||
namespace UniversalEditor.DataFormats.Multimedia.Audio.Synthesized.EdLib
|
||||
{
|
||||
public class D00DataFormat : DataFormat
|
||||
{
|
||||
private AdlibBlockType mvarBlockType = AdlibBlockType.MusicData;
|
||||
public AdlibBlockType BlockType { get { return mvarBlockType; } set { mvarBlockType = value; } }
|
||||
|
||||
private byte mvarPlayerVersion = 0x04;
|
||||
public byte PlayerVersion { get { return mvarPlayerVersion; } set { mvarPlayerVersion = value; } }
|
||||
|
||||
private byte mvarTimerSpeed = 0x46;
|
||||
public byte TimerSpeed { get { return mvarTimerSpeed; } set { mvarTimerSpeed = value; } }
|
||||
|
||||
private AdlibSoundcard mvarSoundcard = AdlibSoundcard.Adlib;
|
||||
public AdlibSoundcard Soundcard { get { return mvarSoundcard; } set { mvarSoundcard = value; } }
|
||||
|
||||
private string mvarSongTitle = "";
|
||||
public string SongTitle { get { return mvarSongTitle; } set { mvarSongTitle = value; } }
|
||||
|
||||
private string mvarSongArtist = "";
|
||||
public string SongArtist { get { return mvarSongArtist; } set { mvarSongArtist = value; } }
|
||||
|
||||
private byte[] mvarReserved = new byte[32];
|
||||
public byte[] Reserved { get { return mvarReserved; } set { mvarReserved = value; } }
|
||||
|
||||
protected override void LoadInternal(ref ObjectModel objectModel)
|
||||
{
|
||||
Reader br = base.Accessor.Reader;
|
||||
byte[] magic = br.ReadBytes(6); // 'J', 'C', 'H', 0x26, 0x02, 0x66
|
||||
if (!magic.Match(new byte[] { (byte)'J', (byte)'C', (byte)'H', 0x26, 0x02, 0x66 }))
|
||||
throw new InvalidDataFormatException();
|
||||
|
||||
byte blockType = br.ReadByte(); // 0x00 for music data
|
||||
if (blockType == 0)
|
||||
{
|
||||
mvarBlockType = ((AdlibBlockType)blockType);
|
||||
}
|
||||
else
|
||||
{
|
||||
mvarBlockType = AdlibBlockType.Unknown;
|
||||
}
|
||||
|
||||
mvarPlayerVersion = br.ReadByte(); // Required player version; usually 0x04
|
||||
mvarTimerSpeed = br.ReadByte(); // Timer speed for the block; usually 0x46
|
||||
byte numberOfMusicAndSFX = br.ReadByte(); // Number of music and SFX; usually 0x01
|
||||
|
||||
byte soundCard = br.ReadByte(); // Soundcard; usually 0x00 - Adlib
|
||||
if (soundCard == 0)
|
||||
{
|
||||
mvarSoundcard = ((AdlibSoundcard)soundCard);
|
||||
}
|
||||
else
|
||||
{
|
||||
mvarSoundcard = AdlibSoundcard.Unknown;
|
||||
}
|
||||
|
||||
mvarSongTitle = br.ReadFixedLengthString(32); // 32 bytes name of the music
|
||||
mvarSongArtist = br.ReadFixedLengthString(32); // 32 bytes name of composer
|
||||
mvarReserved = br.ReadBytes(32); // 32 bytes reserved for future expansion
|
||||
|
||||
short ptrTpoin = br.ReadInt16(); // Pointer to "Tpoin" tables
|
||||
short ptrSeqPointer = br.ReadInt16(); // Pointer to "SeqPointer" tables
|
||||
short ptrInstrument = br.ReadInt16(); // Pointer to "Instrument" tables
|
||||
short ptrDataInfo = br.ReadInt16(); // Pointer to "DataInfo" tables
|
||||
short ptrSpecial = br.ReadInt16(); // Pointer to "Special" tables (SpFX)
|
||||
short endMark = br.ReadInt16(); // Endmark (0xFFFF)
|
||||
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
protected override void SaveInternal(ObjectModel objectModel)
|
||||
{
|
||||
Writer bw = base.Accessor.Writer;
|
||||
bw.WriteBytes(new byte[] { 0x4A, 0x43, 0x48, 0x26, 0x02, 0x66 });
|
||||
switch (mvarBlockType)
|
||||
{
|
||||
case AdlibBlockType.MusicData:
|
||||
{
|
||||
bw.WriteByte((byte)0);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
bw.WriteByte((byte)0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bw.WriteByte(mvarPlayerVersion);
|
||||
bw.WriteByte(mvarTimerSpeed);
|
||||
|
||||
bw.WriteByte(1); // numberOfMusicAndSFX: Number of music and SFX; usually 0x01
|
||||
|
||||
switch (mvarSoundcard)
|
||||
{
|
||||
case AdlibSoundcard.Adlib:
|
||||
{
|
||||
bw.WriteByte((byte)0);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
bw.WriteByte((byte)0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bw.WriteFixedLengthString(mvarSongTitle, 32); // 32 bytes name of the music
|
||||
bw.WriteFixedLengthString(mvarSongArtist, 32); // 32 bytes name of composer
|
||||
bw.WriteFixedLengthBytes(mvarReserved, 32); // 32 bytes reserved for future expansion
|
||||
|
||||
short ptrTpoin = 0;
|
||||
bw.WriteInt16(ptrTpoin); // Pointer to "Tpoin" tables
|
||||
|
||||
short ptrSeqPointer = 0; // Pointer to "SeqPointer" tables
|
||||
bw.WriteInt16(ptrSeqPointer);
|
||||
|
||||
short ptrInstrument = 0; // Pointer to "Instrument" tables
|
||||
bw.WriteInt16(ptrInstrument);
|
||||
|
||||
short ptrDataInfo = 0; // Pointer to "DataInfo" tables
|
||||
bw.WriteInt16(ptrDataInfo);
|
||||
|
||||
short ptrSpecial = 0; // Pointer to "Special" tables (SpFX)
|
||||
bw.WriteInt16(ptrSpecial);
|
||||
|
||||
short endMark = 0; // Endmark (0xFFFF)
|
||||
bw.WriteInt16(endMark);
|
||||
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
//
|
||||
// ADXBlock.cs
|
||||
//
|
||||
// Author:
|
||||
// Mike Becker <alcexhim@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2010-2019 Mike Becker
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace UniversalEditor.DataFormats.Multimedia.Audio.Waveform.CRI.ADX
|
||||
{
|
||||
public class ADXBlock
|
||||
{
|
||||
private ushort mvarScale = 0;
|
||||
/// <summary>
|
||||
/// The scale is a 16bit unsigned integer (big-endian like the header) which is essentially the amplification of all the samples in that block.
|
||||
/// </summary>
|
||||
public ushort Scale { get { return mvarScale; } set { mvarScale = value; } }
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,266 @@
|
||||
//
|
||||
// ADXDocument.cs
|
||||
//
|
||||
// Author:
|
||||
// Mike Becker <alcexhim@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2010-2019 Mike Becker
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using UniversalEditor.IO;
|
||||
using UniversalEditor.ObjectModels.Multimedia.Audio.Waveform;
|
||||
|
||||
namespace UniversalEditor.DataFormats.Multimedia.Audio.Waveform.CRI.ADX
|
||||
{
|
||||
public class ADXDataFormat : DataFormat
|
||||
{
|
||||
private byte[] mvarSignature = new byte[] { 0x80, 0x00 };
|
||||
public byte[] Signature { get { return mvarSignature; } set { mvarSignature = value; } }
|
||||
|
||||
public ushort CopyrightOffset { get { return (ushort)(mvarAdditionalPadding.Length + 2); } }
|
||||
|
||||
private ADXEncodingType mvarEncodingType = ADXEncodingType.StandardADX;
|
||||
public ADXEncodingType EncodingType { get { return mvarEncodingType; } set { mvarEncodingType = value; } }
|
||||
|
||||
private byte mvarBlockSize = 0;
|
||||
public byte BlockSize { get { return mvarBlockSize; } set { mvarBlockSize = value; } }
|
||||
private byte mvarSampleBitDepth = 0;
|
||||
public byte SampleBitDepth { get { return mvarSampleBitDepth; } set { mvarSampleBitDepth = value; } }
|
||||
private byte mvarChannelCount = 0;
|
||||
public byte ChannelCount { get { return mvarChannelCount; } set { mvarChannelCount = value; } }
|
||||
private uint mvarSampleRate = 0;
|
||||
public uint SampleRate { get { return mvarSampleRate; } set { mvarSampleRate = value; } }
|
||||
private uint mvarTotalSamples = 0;
|
||||
public uint TotalSamples { get { return mvarTotalSamples; } set { mvarTotalSamples = value; } }
|
||||
private ushort mvarHighpassFrequency = 0;
|
||||
public ushort HighpassFrequency { get { return mvarHighpassFrequency; } set { mvarHighpassFrequency = value; } }
|
||||
|
||||
private ADXVersion mvarVersion = ADXVersion.ADXVersion3;
|
||||
public ADXVersion Version { get { return mvarVersion; } set { mvarVersion = value; } }
|
||||
|
||||
private byte mvarFlags = 0;
|
||||
public byte Flags { get { return mvarFlags; } set { mvarFlags = value; } }
|
||||
|
||||
private uint mvarUnknown = 0;
|
||||
public uint Unknown { get { return mvarUnknown; } set { mvarUnknown = value; } }
|
||||
|
||||
private bool mvarLoopEnabled = false; // uint
|
||||
public bool LoopEnabled { get { return mvarLoopEnabled; } set { mvarLoopEnabled = value; } }
|
||||
|
||||
private uint mvarLoopBeginSampleIndex = 0;
|
||||
public uint LoopBeginSampleIndex { get { return mvarLoopBeginSampleIndex; } set { mvarLoopBeginSampleIndex = value; } }
|
||||
private uint mvarLoopBeginByteIndex = 0;
|
||||
public uint LoopBeginByteIndex { get { return mvarLoopBeginByteIndex; } set { mvarLoopBeginByteIndex = value; } }
|
||||
private uint mvarLoopEndSampleIndex = 0;
|
||||
public uint LoopEndSampleIndex { get { return mvarLoopEndSampleIndex; } set { mvarLoopEndSampleIndex = value; } }
|
||||
private uint mvarLoopEndByteIndex = 0;
|
||||
public uint LoopEndByteIndex { get { return mvarLoopEndByteIndex; } set { mvarLoopEndByteIndex = value; } }
|
||||
|
||||
private byte[] mvarAdditionalPadding = new byte[] { };
|
||||
public byte[] AdditionalPadding { get { return mvarAdditionalPadding; } set { mvarAdditionalPadding = value; } }
|
||||
|
||||
public double[] GetPredictionCoefficients()
|
||||
{
|
||||
double M_PI = Math.Acos(-1.0);
|
||||
double a, b, c;
|
||||
a = Math.Sqrt(2.0) - Math.Cos(2.0 * M_PI * ((double)mvarHighpassFrequency / mvarSampleRate));
|
||||
b = Math.Sqrt(2.0) - 1.0;
|
||||
c = (a - Math.Sqrt((a + b) * (a - b))) / b; //(a+b)*(a-b) = a*a-b*b, however the simpler formula loses accuracy in floating point
|
||||
double[] coefficient = new double[] { c * 2.0, -(c * c) };
|
||||
return coefficient;
|
||||
}
|
||||
public uint decode_adx_standard(ref short[] buffer, uint samples_needed, bool looping_enabled)
|
||||
{
|
||||
int[] past_samples = new int[mvarChannelCount * 2]; // Previously decoded samples from each channel, zeroed at start (size = 2*channel_count)
|
||||
uint sample_index = 0; // sample_index is the index of sample set that needs to be decoded next
|
||||
|
||||
// buffer is where the decoded samples will be put
|
||||
// samples_needed states how many sample 'sets' (one sample from every channel) need to be decoded to fill the buffer
|
||||
// looping_enabled is a boolean flag to control use of the built-in loop
|
||||
// Returns the number of sample 'sets' in the buffer that could not be filled (EOS)
|
||||
uint samples_per_block = (uint)((mvarBlockSize - 2) * 8 / mvarSampleBitDepth);
|
||||
short[] scale = new short[mvarChannelCount];
|
||||
if (looping_enabled && mvarLoopEnabled) looping_enabled = false;
|
||||
|
||||
// Loop until the requested number of samples are decoded, or the end of file is reached
|
||||
while (samples_needed > 0 && sample_index < mvarTotalSamples)
|
||||
{
|
||||
// Calculate the number of samples that are left to be decoded in the current block
|
||||
uint sample_offset = sample_index % samples_per_block;
|
||||
uint samples_can_get = samples_per_block - sample_offset;
|
||||
|
||||
// Clamp the samples we can get during this run if they won't fit in the buffer
|
||||
if (samples_can_get > samples_needed)
|
||||
{
|
||||
samples_can_get = samples_needed;
|
||||
}
|
||||
|
||||
// Clamp the number of samples to be acquired if the stream isn't long enough or the loop trigger is nearby
|
||||
if (looping_enabled && sample_index + samples_can_get > mvarLoopEndSampleIndex)
|
||||
{
|
||||
samples_can_get = mvarLoopEndSampleIndex - sample_index;
|
||||
}
|
||||
else if (sample_index + samples_can_get > mvarTotalSamples)
|
||||
{
|
||||
samples_can_get = mvarTotalSamples - sample_index;
|
||||
}
|
||||
|
||||
// Calculate the bit address of the start of the frame that sample_index resides in and record that location
|
||||
ulong started_at = (ulong)(CopyrightOffset + 4 + sample_index / samples_per_block * mvarBlockSize * mvarChannelCount) * 8;
|
||||
|
||||
// Read the scale values from the start of each block in this frame
|
||||
for (uint i = 0; i < mvarChannelCount; ++i)
|
||||
{
|
||||
// assuming system.io.binaryreader br
|
||||
|
||||
// br.Seek( started_at + mvarBlockSize * i * 8 );
|
||||
// scale[i] = br.ReadInt16();
|
||||
}
|
||||
|
||||
// Pre-calculate the stop value for sample_offset
|
||||
uint sample_endoffset = sample_offset + samples_can_get;
|
||||
|
||||
// Save the bitstream address of the first sample immediately after the scale in the first block of the frame
|
||||
started_at += 16;
|
||||
double[] coefficient = GetPredictionCoefficients();
|
||||
int sample_error = 0;
|
||||
int ptrBuffer = 0;
|
||||
while (sample_offset < sample_endoffset)
|
||||
{
|
||||
for (uint i = 0; i < mvarChannelCount; ++i)
|
||||
{
|
||||
// Predict the next sample
|
||||
double sample_prediction = coefficient[0] * past_samples[i * 2 + 0] + coefficient[1] * past_samples[i * 2 + 1];
|
||||
|
||||
// Seek to the sample offset, read and sign extend it to a 32bit integer
|
||||
// Implementing sign extension is left as an exercise for the reader
|
||||
// The sign extension will also need to include a endian adjustment if there are more than 8 bits
|
||||
|
||||
// br.Seek( started_at + mvarSampleBitDepth * sample_offset + mvarBlockSize * 8 * i );
|
||||
// int sample_error = br.Read( mvarSampleBitDepth );
|
||||
// sample_error = sign_extend( sample_error, mvarSampleBitDepth);
|
||||
|
||||
// Scale the error correction value
|
||||
sample_error *= scale[i];
|
||||
|
||||
// Calculate the sample by combining the prediction with the error correction
|
||||
int sample = sample_error + (int)sample_prediction;
|
||||
|
||||
// Update the past samples with the newer sample
|
||||
past_samples[i * 2 + 1] = past_samples[i * 2 + 0];
|
||||
past_samples[i * 2 + 0] = sample;
|
||||
|
||||
// Clamp the decoded sample to the valid range for a 16bit integer
|
||||
if (sample > 32767)
|
||||
{
|
||||
sample = 32767;
|
||||
}
|
||||
else if (sample < -32768)
|
||||
{
|
||||
sample = -32768;
|
||||
}
|
||||
|
||||
// Save the sample to the buffer then advance one place
|
||||
buffer[ptrBuffer] = (short)sample; ptrBuffer++;
|
||||
}
|
||||
++sample_offset; // We've decoded one sample from every block, advance block offset by 1
|
||||
++sample_index; // This also means we're one sample further into the stream
|
||||
--samples_needed; // And so there is one less set of samples that need to be decoded
|
||||
}
|
||||
|
||||
// Check if we hit the loop end marker, if we did we need to jump to the loop start
|
||||
if (looping_enabled && sample_index == mvarLoopEndSampleIndex)
|
||||
{
|
||||
sample_index = mvarLoopBeginSampleIndex;
|
||||
}
|
||||
}
|
||||
return samples_needed;
|
||||
}
|
||||
|
||||
private static DataFormatReference _dfr = null;
|
||||
protected override DataFormatReference MakeReferenceInternal()
|
||||
{
|
||||
if (_dfr == null)
|
||||
{
|
||||
_dfr = base.MakeReferenceInternal();
|
||||
_dfr.Capabilities.Add(typeof(WaveformAudioObjectModel), DataFormatCapabilities.All);
|
||||
}
|
||||
return _dfr;
|
||||
}
|
||||
|
||||
protected override void LoadInternal(ref ObjectModel objectModel)
|
||||
{
|
||||
WaveformAudioObjectModel wave = (objectModel as WaveformAudioObjectModel);
|
||||
if (wave == null)
|
||||
throw new ObjectModelNotSupportedException();
|
||||
|
||||
Reader reader = base.Accessor.Reader;
|
||||
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
protected override void SaveInternal(ObjectModel objectModel)
|
||||
{
|
||||
WaveformAudioObjectModel wave = (objectModel as WaveformAudioObjectModel);
|
||||
if (wave == null)
|
||||
throw new ObjectModelNotSupportedException();
|
||||
|
||||
Writer bw = base.Accessor.Writer;
|
||||
bw.WriteBytes(mvarSignature);
|
||||
bw.WriteUInt16(CopyrightOffset);
|
||||
bw.WriteByte((byte)mvarEncodingType);
|
||||
bw.WriteByte(mvarBlockSize);
|
||||
bw.WriteByte(mvarSampleBitDepth);
|
||||
bw.WriteByte(mvarChannelCount);
|
||||
bw.WriteUInt32(mvarSampleRate);
|
||||
bw.WriteUInt32(mvarTotalSamples);
|
||||
bw.WriteUInt16(mvarHighpassFrequency);
|
||||
bw.WriteByte((byte)mvarVersion);
|
||||
bw.WriteByte(mvarFlags);
|
||||
bw.WriteUInt32(mvarUnknown);
|
||||
|
||||
if (mvarVersion == ADXVersion.ADXVersion3 || mvarVersion == ADXVersion.ADXVersion3DifferentDecoder)
|
||||
{
|
||||
// Write the v3 fields here
|
||||
bw.WriteBoolean(mvarLoopEnabled);
|
||||
bw.WriteUInt32(mvarLoopBeginSampleIndex);
|
||||
bw.WriteUInt32(mvarLoopBeginByteIndex);
|
||||
bw.WriteUInt32(mvarLoopEndSampleIndex);
|
||||
bw.WriteUInt32(mvarLoopEndByteIndex);
|
||||
bw.WriteBytes(new byte[] { 0, 0, 0, 0 });
|
||||
bw.WriteBytes(new byte[] { 0, 0, 0, 0 });
|
||||
bw.WriteBytes(new byte[] { 0, 0, 0, 0 });
|
||||
}
|
||||
else if (mvarVersion == ADXVersion.ADXVersion4 || mvarVersion == ADXVersion.ADXVersion4WithoutLooping)
|
||||
{
|
||||
bw.WriteBytes(new byte[] { 0, 0, 0, 0 });
|
||||
bw.WriteBytes(new byte[] { 0, 0, 0, 0 });
|
||||
bw.WriteBytes(new byte[] { 0, 0, 0, 0 });
|
||||
bw.WriteBoolean(mvarLoopEnabled);
|
||||
bw.WriteUInt32(mvarLoopBeginSampleIndex);
|
||||
bw.WriteUInt32(mvarLoopBeginByteIndex);
|
||||
bw.WriteUInt32(mvarLoopEndSampleIndex);
|
||||
bw.WriteUInt32(mvarLoopEndByteIndex);
|
||||
}
|
||||
bw.WriteBytes(mvarAdditionalPadding);
|
||||
bw.WriteFixedLengthString("(c)CRI");
|
||||
|
||||
// Audio data starts here!
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,254 @@
|
||||
//
|
||||
// ADXDocument.cs
|
||||
//
|
||||
// Author:
|
||||
// Mike Becker <alcexhim@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2010-2019 Mike Becker
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using UniversalEditor.IO;
|
||||
|
||||
namespace UniversalEditor.DataFormats.Multimedia.Audio.Waveform.CRI.ADX
|
||||
{
|
||||
public class ADXDataFormat : DataFormat
|
||||
{
|
||||
private byte[] mvarSignature = new byte[] { 0x80, 0x00 };
|
||||
public byte[] Signature { get { return mvarSignature; } set { mvarSignature = value; } }
|
||||
|
||||
public ushort CopyrightOffset { get { return (ushort)(mvarAdditionalPadding.Length + 2); } }
|
||||
|
||||
private ADXEncodingType mvarEncodingType = ADXEncodingType.StandardADX;
|
||||
public ADXEncodingType EncodingType { get { return mvarEncodingType; } set { mvarEncodingType = value; } }
|
||||
|
||||
private byte mvarBlockSize = 0;
|
||||
public byte BlockSize { get { return mvarBlockSize; } set { mvarBlockSize = value; } }
|
||||
private byte mvarSampleBitDepth = 0;
|
||||
public byte SampleBitDepth { get { return mvarSampleBitDepth; } set { mvarSampleBitDepth = value; } }
|
||||
private byte mvarChannelCount = 0;
|
||||
public byte ChannelCount { get { return mvarChannelCount; } set { mvarChannelCount = value; } }
|
||||
private uint mvarSampleRate = 0;
|
||||
public uint SampleRate { get { return mvarSampleRate; } set { mvarSampleRate = value; } }
|
||||
private uint mvarTotalSamples = 0;
|
||||
public uint TotalSamples { get { return mvarTotalSamples; } set { mvarTotalSamples = value; } }
|
||||
private ushort mvarHighpassFrequency = 0;
|
||||
public ushort HighpassFrequency { get { return mvarHighpassFrequency; } set { mvarHighpassFrequency = value; } }
|
||||
|
||||
private ADXVersion mvarVersion = ADXVersion.ADXVersion3;
|
||||
public ADXVersion Version { get { return mvarVersion; } set { mvarVersion = value; } }
|
||||
|
||||
private byte mvarFlags = 0;
|
||||
public byte Flags { get { return mvarFlags; } set { mvarFlags = value; } }
|
||||
|
||||
private uint mvarUnknown = 0;
|
||||
public uint Unknown { get { return mvarUnknown; } set { mvarUnknown = value; } }
|
||||
|
||||
private bool mvarLoopEnabled = false; // uint
|
||||
public bool LoopEnabled { get { return mvarLoopEnabled; } set { mvarLoopEnabled = value; } }
|
||||
|
||||
private uint mvarLoopBeginSampleIndex = 0;
|
||||
public uint LoopBeginSampleIndex { get { return mvarLoopBeginSampleIndex; } set { mvarLoopBeginSampleIndex = value; } }
|
||||
private uint mvarLoopBeginByteIndex = 0;
|
||||
public uint LoopBeginByteIndex { get { return mvarLoopBeginByteIndex; } set { mvarLoopBeginByteIndex = value; } }
|
||||
private uint mvarLoopEndSampleIndex = 0;
|
||||
public uint LoopEndSampleIndex { get { return mvarLoopEndSampleIndex; } set { mvarLoopEndSampleIndex = value; } }
|
||||
private uint mvarLoopEndByteIndex = 0;
|
||||
public uint LoopEndByteIndex { get { return mvarLoopEndByteIndex; } set { mvarLoopEndByteIndex = value; } }
|
||||
|
||||
private byte[] mvarAdditionalPadding = new byte[] { };
|
||||
public byte[] AdditionalPadding { get { return mvarAdditionalPadding; } set { mvarAdditionalPadding = value; } }
|
||||
|
||||
public double[] GetPredictionCoefficients()
|
||||
{
|
||||
double M_PI = Math.Acos(-1.0);
|
||||
double a, b, c;
|
||||
a = Math.Sqrt(2.0) - Math.Cos(2.0 * M_PI * ((double)mvarHighpassFrequency / mvarSampleRate));
|
||||
b = Math.Sqrt(2.0) - 1.0;
|
||||
c = (a - Math.Sqrt((a + b) * (a - b))) / b; //(a+b)*(a-b) = a*a-b*b, however the simpler formula loses accuracy in floating point
|
||||
double[] coefficient = new double[] { c * 2.0, -(c * c) };
|
||||
return coefficient;
|
||||
}
|
||||
public uint decode_adx_standard(ref short[] buffer, uint samples_needed, bool looping_enabled)
|
||||
{
|
||||
int[] past_samples = new int[mvarChannelCount * 2]; // Previously decoded samples from each channel, zeroed at start (size = 2*channel_count)
|
||||
uint sample_index = 0; // sample_index is the index of sample set that needs to be decoded next
|
||||
|
||||
// buffer is where the decoded samples will be put
|
||||
// samples_needed states how many sample 'sets' (one sample from every channel) need to be decoded to fill the buffer
|
||||
// looping_enabled is a boolean flag to control use of the built-in loop
|
||||
// Returns the number of sample 'sets' in the buffer that could not be filled (EOS)
|
||||
uint samples_per_block = (uint)((mvarBlockSize - 2) * 8 / mvarSampleBitDepth);
|
||||
short[] scale = new short[mvarChannelCount];
|
||||
if (looping_enabled && mvarLoopEnabled) looping_enabled = false;
|
||||
|
||||
// Loop until the requested number of samples are decoded, or the end of file is reached
|
||||
while (samples_needed > 0 && sample_index < mvarTotalSamples)
|
||||
{
|
||||
// Calculate the number of samples that are left to be decoded in the current block
|
||||
uint sample_offset = sample_index % samples_per_block;
|
||||
uint samples_can_get = samples_per_block - sample_offset;
|
||||
|
||||
// Clamp the samples we can get during this run if they won't fit in the buffer
|
||||
if (samples_can_get > samples_needed)
|
||||
{
|
||||
samples_can_get = samples_needed;
|
||||
}
|
||||
|
||||
// Clamp the number of samples to be acquired if the stream isn't long enough or the loop trigger is nearby
|
||||
if (looping_enabled && sample_index + samples_can_get > mvarLoopEndSampleIndex)
|
||||
{
|
||||
samples_can_get = mvarLoopEndSampleIndex - sample_index;
|
||||
}
|
||||
else if (sample_index + samples_can_get > mvarTotalSamples)
|
||||
{
|
||||
samples_can_get = mvarTotalSamples - sample_index;
|
||||
}
|
||||
|
||||
// Calculate the bit address of the start of the frame that sample_index resides in and record that location
|
||||
ulong started_at = (ulong)(CopyrightOffset + 4 + sample_index / samples_per_block * mvarBlockSize * mvarChannelCount) * 8;
|
||||
|
||||
// Read the scale values from the start of each block in this frame
|
||||
for (uint i = 0; i < mvarChannelCount; ++i)
|
||||
{
|
||||
// assuming system.io.binaryreader br
|
||||
|
||||
// br.Seek( started_at + mvarBlockSize * i * 8 );
|
||||
// scale[i] = br.ReadInt16();
|
||||
}
|
||||
|
||||
// Pre-calculate the stop value for sample_offset
|
||||
uint sample_endoffset = sample_offset + samples_can_get;
|
||||
|
||||
// Save the bitstream address of the first sample immediately after the scale in the first block of the frame
|
||||
started_at += 16;
|
||||
double[] coefficient = GetPredictionCoefficients();
|
||||
int sample_error = 0;
|
||||
int ptrBuffer = 0;
|
||||
while (sample_offset < sample_endoffset)
|
||||
{
|
||||
for (uint i = 0; i < mvarChannelCount; ++i)
|
||||
{
|
||||
// Predict the next sample
|
||||
double sample_prediction = coefficient[0] * past_samples[i * 2 + 0] + coefficient[1] * past_samples[i * 2 + 1];
|
||||
|
||||
// Seek to the sample offset, read and sign extend it to a 32bit integer
|
||||
// Implementing sign extension is left as an exercise for the reader
|
||||
// The sign extension will also need to include a endian adjustment if there are more than 8 bits
|
||||
|
||||
// br.Seek( started_at + mvarSampleBitDepth * sample_offset + mvarBlockSize * 8 * i );
|
||||
// int sample_error = br.Read( mvarSampleBitDepth );
|
||||
// sample_error = sign_extend( sample_error, mvarSampleBitDepth);
|
||||
|
||||
// Scale the error correction value
|
||||
sample_error *= scale[i];
|
||||
|
||||
// Calculate the sample by combining the prediction with the error correction
|
||||
int sample = sample_error + (int)sample_prediction;
|
||||
|
||||
// Update the past samples with the newer sample
|
||||
past_samples[i * 2 + 1] = past_samples[i * 2 + 0];
|
||||
past_samples[i * 2 + 0] = sample;
|
||||
|
||||
// Clamp the decoded sample to the valid range for a 16bit integer
|
||||
if (sample > 32767)
|
||||
{
|
||||
sample = 32767;
|
||||
}
|
||||
else if (sample < -32768)
|
||||
{
|
||||
sample = -32768;
|
||||
}
|
||||
|
||||
// Save the sample to the buffer then advance one place
|
||||
buffer[ptrBuffer] = (short)sample; ptrBuffer++;
|
||||
}
|
||||
++sample_offset; // We've decoded one sample from every block, advance block offset by 1
|
||||
++sample_index; // This also means we're one sample further into the stream
|
||||
--samples_needed; // And so there is one less set of samples that need to be decoded
|
||||
}
|
||||
|
||||
// Check if we hit the loop end marker, if we did we need to jump to the loop start
|
||||
if (looping_enabled && sample_index == mvarLoopEndSampleIndex)
|
||||
{
|
||||
sample_index = mvarLoopBeginSampleIndex;
|
||||
}
|
||||
}
|
||||
return samples_needed;
|
||||
}
|
||||
|
||||
protected override void LoadInternal(ref ObjectModel objectModel)
|
||||
{
|
||||
WaveformAudioObjectModel wave = (objectModel as WaveformAudioObjectModel);
|
||||
if (wave == null)
|
||||
throw new ObjectModelNotSupportedException();
|
||||
|
||||
Reader reader = base.Accessor.Reader;
|
||||
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
protected override void SaveInternal(ObjectModel objectModel)
|
||||
{
|
||||
WaveformAudioObjectModel wave = (objectModel as WaveformAudioObjectModel);
|
||||
if (wave == null)
|
||||
throw new ObjectModelNotSupportedException();
|
||||
|
||||
Writer bw = base.Accessor.Writer;
|
||||
bw.WriteBytes(mvarSignature);
|
||||
bw.WriteUInt16(CopyrightOffset);
|
||||
bw.WriteByte((byte)mvarEncodingType);
|
||||
bw.WriteByte(mvarBlockSize);
|
||||
bw.WriteByte(mvarSampleBitDepth);
|
||||
bw.WriteByte(mvarChannelCount);
|
||||
bw.WriteUInt32(mvarSampleRate);
|
||||
bw.WriteUInt32(mvarTotalSamples);
|
||||
bw.WriteUInt16(mvarHighpassFrequency);
|
||||
bw.WriteByte((byte)mvarVersion);
|
||||
bw.WriteByte(mvarFlags);
|
||||
bw.WriteUInt32(mvarUnknown);
|
||||
|
||||
if (mvarVersion == ADXVersion.ADXVersion3 || mvarVersion == ADXVersion.ADXVersion3DifferentDecoder)
|
||||
{
|
||||
// Write the v3 fields here
|
||||
bw.WriteBoolean(mvarLoopEnabled);
|
||||
bw.WriteUInt32(mvarLoopBeginSampleIndex);
|
||||
bw.WriteUInt32(mvarLoopBeginByteIndex);
|
||||
bw.WriteUInt32(mvarLoopEndSampleIndex);
|
||||
bw.WriteUInt32(mvarLoopEndByteIndex);
|
||||
bw.WriteBytes(new byte[] { 0, 0, 0, 0 });
|
||||
bw.WriteBytes(new byte[] { 0, 0, 0, 0 });
|
||||
bw.WriteBytes(new byte[] { 0, 0, 0, 0 });
|
||||
}
|
||||
else if (mvarVersion == ADXVersion.ADXVersion4 || mvarVersion == ADXVersion.ADXVersion4WithoutLooping)
|
||||
{
|
||||
bw.WriteBytes(new byte[] { 0, 0, 0, 0 });
|
||||
bw.WriteBytes(new byte[] { 0, 0, 0, 0 });
|
||||
bw.WriteBytes(new byte[] { 0, 0, 0, 0 });
|
||||
bw.WriteBoolean(mvarLoopEnabled);
|
||||
bw.WriteUInt32(mvarLoopBeginSampleIndex);
|
||||
bw.WriteUInt32(mvarLoopBeginByteIndex);
|
||||
bw.WriteUInt32(mvarLoopEndSampleIndex);
|
||||
bw.WriteUInt32(mvarLoopEndByteIndex);
|
||||
}
|
||||
bw.WriteBytes(mvarAdditionalPadding);
|
||||
bw.WriteFixedLengthString("(c)CRI");
|
||||
|
||||
// Audio data starts here!
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
//
|
||||
// ADXEncodingType.cs
|
||||
//
|
||||
// Author:
|
||||
// Mike Becker <alcexhim@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2010-2019 Mike Becker
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace UniversalEditor.DataFormats.Multimedia.Audio.Waveform.CRI.ADX
|
||||
{
|
||||
public enum ADXEncodingType : byte
|
||||
{
|
||||
StandardADX = 0x03,
|
||||
ADXWithExponentialScale = 0x04,
|
||||
AHX10 = 0x10,
|
||||
AHX11 = 0x11
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
//
|
||||
// ADXVersion.cs
|
||||
//
|
||||
// Author:
|
||||
// Mike Becker <alcexhim@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2010-2019 Mike Becker
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace UniversalEditor.DataFormats.Multimedia.Audio.Waveform.CRI.ADX
|
||||
{
|
||||
public enum ADXVersion : byte
|
||||
{
|
||||
ADXVersion3DifferentDecoder = 0x02,
|
||||
ADXVersion3 = 0x03,
|
||||
ADXVersion4 = 0x04,
|
||||
ADXVersion4WithoutLooping = 0x05
|
||||
}
|
||||
}
|
||||
@ -316,6 +316,13 @@
|
||||
<Compile Include="DataFormats\Multimedia\Picture\Adobe\Photoshop\PSDLayerMaskParameterFlags.cs" />
|
||||
<Compile Include="DataFormats\Multimedia\Picture\Adobe\Photoshop\PSDLayerCompressionMode.cs" />
|
||||
<Compile Include="DataFormats\Multimedia\Picture\Adobe\Photoshop\Internal\PSDLayer.cs" />
|
||||
<Compile Include="DataFormats\Multimedia\Audio\Waveform\CRI\ADX\ADXBlock.cs" />
|
||||
<Compile Include="DataFormats\Multimedia\Audio\Waveform\CRI\ADX\ADXDataFormat.cs" />
|
||||
<Compile Include="DataFormats\Multimedia\Audio\Waveform\CRI\ADX\ADXEncodingType.cs" />
|
||||
<Compile Include="DataFormats\Multimedia\Audio\Waveform\CRI\ADX\ADXVersion.cs" />
|
||||
<Compile Include="DataFormats\Multimedia\Audio\Synthesized\EdLib\D00DataFormat.cs" />
|
||||
<Compile Include="DataFormats\Multimedia\Audio\Synthesized\EdLib\AdlibSoundcard.cs" />
|
||||
<Compile Include="DataFormats\Multimedia\Audio\Synthesized\EdLib\AdlibBlockType.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Libraries\UniversalEditor.Compression\UniversalEditor.Compression.csproj">
|
||||
@ -363,6 +370,9 @@
|
||||
<Folder Include="DataFormats\Multimedia\Picture\Adobe\" />
|
||||
<Folder Include="DataFormats\Multimedia\Picture\Adobe\Photoshop\" />
|
||||
<Folder Include="DataFormats\Multimedia\Picture\Adobe\Photoshop\Internal\" />
|
||||
<Folder Include="DataFormats\Multimedia\Audio\Waveform\CRI\" />
|
||||
<Folder Include="DataFormats\Multimedia\Audio\Waveform\CRI\ADX\" />
|
||||
<Folder Include="DataFormats\Multimedia\Audio\Synthesized\EdLib\" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
Loading…
x
Reference in New Issue
Block a user