mirror of
https://github.com/blueskythlikesclouds/SonicAudioTools.git
synced 2025-02-08 23:19:44 +01:00
Implement many things and add vgmstream
This commit is contained in:
parent
2131ac6799
commit
6f0437eaf7
BIN
Libraries/at3plusdecoder.dll
Normal file
BIN
Libraries/at3plusdecoder.dll
Normal file
Binary file not shown.
20
Libraries/vgmstream.LICENSE.txt
Normal file
20
Libraries/vgmstream.LICENSE.txt
Normal file
@ -0,0 +1,20 @@
|
||||
Copyright (c) 2008-2010 Adam Gashlin, Fastelbja, Ronny Elfert
|
||||
|
||||
Portions Copyright (c) 2004-2008, Marko Kreen
|
||||
Portions Copyright 2001-2007 jagarl / Kazunori Ueno <jagarl@creator.club.ne.jp>
|
||||
Portions Copyright (c) 1998, Justin Frankel/Nullsoft Inc.
|
||||
Portions Copyright (C) 2006 Nullsoft, Inc.
|
||||
Portions Copyright (c) 2005-2007 Paul Hsieh
|
||||
Portions Public Domain originating with Sun Microsystems
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
BIN
Libraries/vgmstream.dll
Normal file
BIN
Libraries/vgmstream.dll
Normal file
Binary file not shown.
@ -9,9 +9,10 @@
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>AcbEditor</RootNamespace>
|
||||
<AssemblyName>AcbEditor</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
@ -22,6 +23,7 @@
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
|
@ -1,12 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<configSections>
|
||||
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
|
||||
<section name="AcbEditor.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
|
||||
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<section name="AcbEditor.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false"/>
|
||||
</sectionGroup>
|
||||
</configSections>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1"/>
|
||||
</startup>
|
||||
<userSettings>
|
||||
<AcbEditor.Properties.Settings>
|
||||
@ -21,4 +21,4 @@
|
||||
</setting>
|
||||
</AcbEditor.Properties.Settings>
|
||||
</userSettings>
|
||||
</configuration>
|
||||
</configuration>
|
||||
|
@ -9,7 +9,7 @@ using AcbEditor.Properties;
|
||||
using SonicAudioLib;
|
||||
using SonicAudioLib.CriMw;
|
||||
using SonicAudioLib.IO;
|
||||
using SonicAudioLib.Archive;
|
||||
using SonicAudioLib.Archives;
|
||||
|
||||
namespace AcbEditor
|
||||
{
|
||||
@ -17,9 +17,15 @@ namespace AcbEditor
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
if (!File.Exists(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile))
|
||||
{
|
||||
Settings.Default.Reset();
|
||||
Settings.Default.Save();
|
||||
}
|
||||
|
||||
if (args.Length < 1)
|
||||
{
|
||||
Console.WriteLine(Properties.Resources.Description);
|
||||
Console.WriteLine(Resources.Description);
|
||||
Console.ReadLine();
|
||||
return;
|
||||
}
|
||||
@ -72,7 +78,7 @@ namespace AcbEditor
|
||||
long awbPosition = acbReader.GetPosition("AwbFile");
|
||||
if (acbReader.GetLength("AwbFile") > 0)
|
||||
{
|
||||
using (Substream afs2Stream = acbReader.GetSubstream("AwbFile"))
|
||||
using (SubStream afs2Stream = acbReader.GetSubStream("AwbFile"))
|
||||
{
|
||||
cpkMode = !CheckIfAfs2(afs2Stream);
|
||||
|
||||
@ -92,7 +98,7 @@ namespace AcbEditor
|
||||
{
|
||||
cpkMode = false;
|
||||
|
||||
using (Substream extAfs2Stream = acbReader.GetSubstream("StreamAwbAfs2Header"))
|
||||
using (SubStream extAfs2Stream = acbReader.GetSubStream("StreamAwbAfs2Header"))
|
||||
{
|
||||
extAfs2Archive.Read(extAfs2Stream);
|
||||
}
|
||||
@ -103,7 +109,7 @@ namespace AcbEditor
|
||||
}
|
||||
}
|
||||
|
||||
using (Substream waveformTableStream = acbReader.GetSubstream("WaveformTable"))
|
||||
using (SubStream waveformTableStream = acbReader.GetSubStream("WaveformTable"))
|
||||
using (CriTableReader waveformReader = CriTableReader.Create(waveformTableStream))
|
||||
{
|
||||
while (waveformReader.Read())
|
||||
@ -353,7 +359,7 @@ namespace AcbEditor
|
||||
static bool CheckIfAfs2(Stream source)
|
||||
{
|
||||
long oldPosition = source.Position;
|
||||
bool result = EndianStream.ReadCString(source, 4) == "AFS2";
|
||||
bool result = DataStream.ReadCString(source, 4) == "AFS2";
|
||||
source.Seek(oldPosition, SeekOrigin.Begin);
|
||||
|
||||
return result;
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1"/>
|
||||
</startup>
|
||||
</configuration>
|
||||
</configuration>
|
||||
|
@ -1,478 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using SonicAudioLib.IO;
|
||||
|
||||
using NAudio.Wave;
|
||||
using NAudio.Wave.SampleProviders;
|
||||
|
||||
namespace CsbBuilder.Audio
|
||||
{
|
||||
public struct AdxHeader
|
||||
{
|
||||
public ushort Identifier;
|
||||
public ushort DataPosition;
|
||||
public byte EncodeType;
|
||||
public byte BlockLength;
|
||||
public byte SampleBitdepth;
|
||||
public byte ChannelCount;
|
||||
public uint SampleRate;
|
||||
public uint SampleCount;
|
||||
public ushort CutoffFrequency;
|
||||
public ushort Version;
|
||||
public short[][] SampleHistories;
|
||||
}
|
||||
|
||||
public class AdxFileReader : WaveStream
|
||||
{
|
||||
private class SampleHistory
|
||||
{
|
||||
public short Sample1 = 0;
|
||||
public short Sample2 = 0;
|
||||
}
|
||||
|
||||
private Stream source;
|
||||
|
||||
private AdxHeader header;
|
||||
private WaveFormat waveFormat;
|
||||
|
||||
private short coef1;
|
||||
private short coef2;
|
||||
|
||||
private SampleHistory[] histories;
|
||||
|
||||
private int sampleCount;
|
||||
private int readSamples;
|
||||
|
||||
private byte[] previousSamples;
|
||||
|
||||
private double volume = 1;
|
||||
private double pitch = 0;
|
||||
private long delayTime = 0;
|
||||
private DateTime startTime;
|
||||
|
||||
public override WaveFormat WaveFormat
|
||||
{
|
||||
get
|
||||
{
|
||||
return waveFormat;
|
||||
}
|
||||
}
|
||||
|
||||
public override long Length
|
||||
{
|
||||
get
|
||||
{
|
||||
return sampleCount * 2;
|
||||
}
|
||||
}
|
||||
|
||||
public override long Position
|
||||
{
|
||||
get
|
||||
{
|
||||
return readSamples * 2;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsFinished
|
||||
{
|
||||
get
|
||||
{
|
||||
return readSamples >= sampleCount;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsLoopEnabled { get; set; }
|
||||
|
||||
public double Volume
|
||||
{
|
||||
set
|
||||
{
|
||||
volume = value;
|
||||
}
|
||||
}
|
||||
|
||||
public double Pitch
|
||||
{
|
||||
set
|
||||
{
|
||||
pitch = value;
|
||||
}
|
||||
}
|
||||
|
||||
public int DelayTime
|
||||
{
|
||||
set
|
||||
{
|
||||
startTime = DateTime.Now;
|
||||
delayTime = value * 10000;
|
||||
}
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (IsFinished && !IsLoopEnabled)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (delayTime > 0)
|
||||
{
|
||||
if ((DateTime.Now - startTime).Ticks < delayTime)
|
||||
{
|
||||
return count;
|
||||
}
|
||||
|
||||
delayTime = 0;
|
||||
}
|
||||
|
||||
int length = count;
|
||||
|
||||
while ((length % (header.ChannelCount * 64)) != 0)
|
||||
{
|
||||
length++;
|
||||
}
|
||||
|
||||
byte[] samples = new byte[length];
|
||||
|
||||
int currentLength = 0;
|
||||
|
||||
while (currentLength < length)
|
||||
{
|
||||
int sampleLength = GetNextSamples(samples, currentLength);
|
||||
|
||||
if (sampleLength < 0)
|
||||
{
|
||||
count = count > currentLength ? currentLength : count;
|
||||
break;
|
||||
}
|
||||
|
||||
currentLength = sampleLength;
|
||||
}
|
||||
|
||||
if (previousSamples != null)
|
||||
{
|
||||
samples = previousSamples.Concat(samples).ToArray();
|
||||
length = samples.Length;
|
||||
}
|
||||
|
||||
if (length > count)
|
||||
{
|
||||
previousSamples = samples.Skip(count).ToArray();
|
||||
}
|
||||
|
||||
else if (length < count)
|
||||
{
|
||||
previousSamples = null;
|
||||
count = length;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
previousSamples = null;
|
||||
}
|
||||
|
||||
Array.Copy(samples, 0, buffer, offset, count);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
private int GetNextSamples(byte[] destination, int startIndex)
|
||||
{
|
||||
short[][] channelSamples = new short[header.ChannelCount][];
|
||||
|
||||
for (int i = 0; i < header.ChannelCount; i++)
|
||||
{
|
||||
if (!DecodeBlock(i, out short[] samples))
|
||||
{
|
||||
if (IsLoopEnabled)
|
||||
{
|
||||
Reset();
|
||||
DecodeBlock(i, out samples);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
readSamples = sampleCount;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
channelSamples[i] = samples;
|
||||
}
|
||||
|
||||
int position = startIndex;
|
||||
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
for (int j = 0; j < header.ChannelCount; j++)
|
||||
{
|
||||
short sample = (short)(channelSamples[j][i] * volume);
|
||||
|
||||
destination[position++] = (byte)sample;
|
||||
destination[position++] = (byte)(sample >> 8);
|
||||
}
|
||||
}
|
||||
|
||||
return position;
|
||||
}
|
||||
|
||||
private bool DecodeBlock(int c, out short[] samples)
|
||||
{
|
||||
int scale = EndianStream.ReadUInt16BE(source) + 1;
|
||||
|
||||
// There seems to be a null sample block at the end of every adx file.
|
||||
// It always added a half second delay between intro and loop, so
|
||||
// I wanted to get rid of it.
|
||||
if (scale > short.MaxValue + 1)
|
||||
{
|
||||
samples = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
samples = new short[32];
|
||||
|
||||
int sampleByte = 0;
|
||||
|
||||
SampleHistory history = histories[c];
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
if ((i % 2) == 0)
|
||||
{
|
||||
sampleByte = source.ReadByte();
|
||||
}
|
||||
|
||||
int sample = ((i & 1) != 0 ?
|
||||
(sampleByte & 7) - (sampleByte & 8) :
|
||||
((sampleByte & 0x70) - (sampleByte & 0x80)) >> 4) * scale +
|
||||
((coef1 * history.Sample1 + coef2 * history.Sample2) >> 12);
|
||||
|
||||
sample = sample > short.MaxValue ? short.MaxValue : sample < short.MinValue ? short.MinValue : sample;
|
||||
|
||||
samples[i] = (short)sample;
|
||||
|
||||
history.Sample2 = history.Sample1;
|
||||
history.Sample1 = (short)sample;
|
||||
|
||||
readSamples++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
source.Seek(header.DataPosition + 4, SeekOrigin.Begin);
|
||||
readSamples = 0;
|
||||
}
|
||||
|
||||
public void ReplaceHistories(AdxFileReader reader)
|
||||
{
|
||||
histories = reader.histories;
|
||||
}
|
||||
|
||||
public static AdxHeader LoadHeader(string sourceFileName)
|
||||
{
|
||||
using (Stream source = File.OpenRead(sourceFileName))
|
||||
{
|
||||
return ReadHeader(source);
|
||||
}
|
||||
}
|
||||
|
||||
public static AdxHeader ReadHeader(Stream source)
|
||||
{
|
||||
AdxHeader header = new AdxHeader();
|
||||
header.Identifier = EndianStream.ReadUInt16BE(source);
|
||||
header.DataPosition = EndianStream.ReadUInt16BE(source);
|
||||
header.EncodeType = EndianStream.ReadByte(source);
|
||||
header.BlockLength = EndianStream.ReadByte(source);
|
||||
header.SampleBitdepth = EndianStream.ReadByte(source);
|
||||
header.ChannelCount = EndianStream.ReadByte(source);
|
||||
header.SampleRate = EndianStream.ReadUInt32BE(source);
|
||||
header.SampleCount = EndianStream.ReadUInt32BE(source);
|
||||
header.CutoffFrequency = EndianStream.ReadUInt16BE(source);
|
||||
header.Version = EndianStream.ReadUInt16BE(source);
|
||||
return header;
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
source.Close();
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
public AdxFileReader(string fileName) : this(File.OpenRead(fileName))
|
||||
{
|
||||
}
|
||||
|
||||
public AdxFileReader(Stream source)
|
||||
{
|
||||
this.source = source;
|
||||
|
||||
header = AdxFileReader.ReadHeader(this.source);
|
||||
source.Seek(header.DataPosition + 4, SeekOrigin.Begin);
|
||||
|
||||
// Calculate coefficients
|
||||
double a = Math.Sqrt(2.0);
|
||||
double b = a - Math.Cos(header.CutoffFrequency * Math.PI * 2.0 / header.SampleRate);
|
||||
double c = (b - Math.Sqrt((b - (a - 1.0)) * (a - 1.0 + b))) / (a - 1.0);
|
||||
|
||||
coef1 = (short)(8192.0 * c);
|
||||
coef2 = (short)(c * c * -4096.0);
|
||||
|
||||
histories = new SampleHistory[header.ChannelCount];
|
||||
for (int i = 0; i < histories.Length; i++)
|
||||
{
|
||||
histories[i] = new SampleHistory();
|
||||
}
|
||||
|
||||
sampleCount = (int)(header.SampleCount * header.ChannelCount);
|
||||
waveFormat = new WaveFormat((int)header.SampleRate, 16, header.ChannelCount);
|
||||
}
|
||||
}
|
||||
|
||||
public class ExtendedAdxFileReader : WaveStream
|
||||
{
|
||||
private List<AdxFileReader> readers = new List<AdxFileReader>();
|
||||
private int currentIndex = 0;
|
||||
|
||||
public override long Length
|
||||
{
|
||||
get
|
||||
{
|
||||
long totalLength = 0;
|
||||
|
||||
foreach (AdxFileReader reader in readers)
|
||||
{
|
||||
totalLength += reader.Length;
|
||||
}
|
||||
|
||||
return totalLength;
|
||||
}
|
||||
}
|
||||
|
||||
public override long Position
|
||||
{
|
||||
get
|
||||
{
|
||||
long position = 0;
|
||||
|
||||
foreach (AdxFileReader reader in readers)
|
||||
{
|
||||
if (reader == readers[currentIndex])
|
||||
{
|
||||
position += reader.Position;
|
||||
break;
|
||||
}
|
||||
|
||||
position += reader.Length;
|
||||
}
|
||||
|
||||
return position;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public override WaveFormat WaveFormat
|
||||
{
|
||||
get
|
||||
{
|
||||
return readers[currentIndex].WaveFormat;
|
||||
}
|
||||
}
|
||||
|
||||
public double Volume
|
||||
{
|
||||
set
|
||||
{
|
||||
readers.ForEach(reader => reader.Volume = value);
|
||||
}
|
||||
}
|
||||
|
||||
public double Pitch
|
||||
{
|
||||
set
|
||||
{
|
||||
readers.ForEach(reader => reader.Pitch = value);
|
||||
}
|
||||
}
|
||||
|
||||
public int DelayTime
|
||||
{
|
||||
set
|
||||
{
|
||||
readers.First().DelayTime = value;
|
||||
}
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
int num = readers[currentIndex].Read(buffer, 0, count);
|
||||
|
||||
if ((num < count) && !readers[currentIndex].IsLoopEnabled)
|
||||
{
|
||||
currentIndex++;
|
||||
|
||||
readers[currentIndex].ReplaceHistories(readers[currentIndex - 1]);
|
||||
|
||||
int num2 = readers[currentIndex].Read(buffer, num, count - num);
|
||||
return num + num2;
|
||||
}
|
||||
|
||||
else if (readers[currentIndex].IsFinished && !readers[currentIndex].IsLoopEnabled)
|
||||
{
|
||||
currentIndex++;
|
||||
|
||||
readers[currentIndex].ReplaceHistories(readers[currentIndex - 1]);
|
||||
|
||||
num = readers[currentIndex].Read(buffer, 0, count);
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
readers.ForEach(reader => reader.Dispose());
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
public ExtendedAdxFileReader(params string[] fileNames) : this(fileNames.Select(fileName => File.OpenRead(fileName)).ToArray())
|
||||
{
|
||||
}
|
||||
|
||||
public ExtendedAdxFileReader(params Stream[] sources)
|
||||
{
|
||||
foreach (Stream source in sources)
|
||||
{
|
||||
readers.Add(new AdxFileReader(source));
|
||||
}
|
||||
|
||||
// The last one is the one to loop
|
||||
readers.Last().IsLoopEnabled = true;
|
||||
}
|
||||
}
|
||||
}
|
148
Source/CsbBuilder/Audio/ExtendedWaveStream.cs
Normal file
148
Source/CsbBuilder/Audio/ExtendedWaveStream.cs
Normal file
@ -0,0 +1,148 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using NAudio.Wave;
|
||||
|
||||
namespace CsbBuilder.Audio
|
||||
{
|
||||
public class ExtendedWaveStream : WaveStream
|
||||
{
|
||||
private int currentStreamIndex = 0;
|
||||
private readonly List<WaveStream> streams = new List<WaveStream>();
|
||||
|
||||
private double volume = 1;
|
||||
private double pitch = 0;
|
||||
private long delayTime = 0;
|
||||
private DateTime startTime;
|
||||
|
||||
public override WaveFormat WaveFormat
|
||||
{
|
||||
get
|
||||
{
|
||||
WaveFormat waveFormat = streams[currentStreamIndex].WaveFormat;
|
||||
|
||||
return new WaveFormat(waveFormat.SampleRate + (int)(waveFormat.SampleRate * pitch), waveFormat.Channels);
|
||||
}
|
||||
}
|
||||
|
||||
public override long Length
|
||||
{
|
||||
get
|
||||
{
|
||||
return streams.Sum(reader => reader.Length);
|
||||
}
|
||||
}
|
||||
|
||||
public override long Position
|
||||
{
|
||||
get
|
||||
{
|
||||
return streams.Take(currentStreamIndex).Sum(reader => reader.Length) + streams[currentStreamIndex].Position;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
long position = 0;
|
||||
|
||||
for (int i = 0; i < streams.Count; i++)
|
||||
{
|
||||
if (position + streams[i].Length > value)
|
||||
{
|
||||
currentStreamIndex = i;
|
||||
streams[i].Position = value - position;
|
||||
break;
|
||||
}
|
||||
|
||||
position += streams[i].Length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public double Volume
|
||||
{
|
||||
set
|
||||
{
|
||||
volume = value;
|
||||
}
|
||||
}
|
||||
|
||||
public double Pitch
|
||||
{
|
||||
set
|
||||
{
|
||||
pitch = value;
|
||||
}
|
||||
}
|
||||
|
||||
public int DelayTime
|
||||
{
|
||||
set
|
||||
{
|
||||
startTime = DateTime.Now;
|
||||
delayTime = value * 10000;
|
||||
}
|
||||
}
|
||||
|
||||
public bool ForceLoop { get; set; }
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (delayTime > 0)
|
||||
{
|
||||
if ((DateTime.Now - startTime).Ticks < delayTime)
|
||||
{
|
||||
return count;
|
||||
}
|
||||
|
||||
delayTime = 0;
|
||||
}
|
||||
|
||||
int num = streams[currentStreamIndex].Read(buffer, 0, count);
|
||||
|
||||
if (num < count && currentStreamIndex != streams.Count - 1)
|
||||
{
|
||||
currentStreamIndex++;
|
||||
num += streams[currentStreamIndex].Read(buffer, num, count - num);
|
||||
}
|
||||
|
||||
else if (ForceLoop && num < count && currentStreamIndex == streams.Count - 1)
|
||||
{
|
||||
streams[currentStreamIndex].Position = 0;
|
||||
num += streams[currentStreamIndex].Read(buffer, num, count - num);
|
||||
}
|
||||
|
||||
if (volume != 1)
|
||||
{
|
||||
PostSampleEditor.ApplyVolume(buffer, offset, num, volume);
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
foreach (var reader in streams)
|
||||
{
|
||||
reader.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
public ExtendedWaveStream(params WaveStream[] waveStreams)
|
||||
{
|
||||
if (waveStreams.Length == 0)
|
||||
{
|
||||
throw new ArgumentException("You must at least specify one source!", nameof(waveStreams));
|
||||
}
|
||||
|
||||
streams.AddRange(waveStreams);
|
||||
}
|
||||
}
|
||||
}
|
32
Source/CsbBuilder/Audio/PostSampleEditor.cs
Normal file
32
Source/CsbBuilder/Audio/PostSampleEditor.cs
Normal file
@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CsbBuilder.Audio
|
||||
{
|
||||
public static class PostSampleEditor
|
||||
{
|
||||
public static void ApplyVolume(byte[] buffer, int offset, int count, double volume)
|
||||
{
|
||||
for (int i = offset; i < count; i += 2)
|
||||
{
|
||||
ApplyVolume(buffer, i, volume);
|
||||
}
|
||||
}
|
||||
|
||||
public static void ApplyVolume(byte[] buffer, int offset, double volume)
|
||||
{
|
||||
int sample = (int)((short)(buffer[offset] | buffer[offset + 1] << 8) * volume);
|
||||
|
||||
short sample16 =
|
||||
sample > short.MaxValue ? short.MaxValue :
|
||||
sample < short.MinValue ? short.MinValue :
|
||||
(short)sample;
|
||||
|
||||
buffer[offset] = (byte)sample16;
|
||||
buffer[offset + 1] = (byte)(sample16 >> 8);
|
||||
}
|
||||
}
|
||||
}
|
313
Source/CsbBuilder/Audio/VGMStreamNative.cs
Normal file
313
Source/CsbBuilder/Audio/VGMStreamNative.cs
Normal file
@ -0,0 +1,313 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace CsbBuilder.Audio
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a static class for calling native VGMSTREAM methods.
|
||||
/// </summary>
|
||||
public static class VGMStreamNative
|
||||
{
|
||||
/// <summary>
|
||||
/// Path of the VGMSTREAM DLL file.
|
||||
/// </summary>
|
||||
public const string DllName = "vgmstream.dll";
|
||||
|
||||
/// <summary>
|
||||
/// Size of VGMSTREAM structure.
|
||||
/// </summary>
|
||||
public const int SizeOfVgmStream = 152;
|
||||
|
||||
/// <summary>
|
||||
/// Size of VGMSTREAMCHANNEL structure.
|
||||
/// </summary>
|
||||
public const int SizeOfVgmStreamChannel = 552;
|
||||
|
||||
#region VGMStream Exports
|
||||
/// <summary>
|
||||
/// Initializes a VGMSTREAM from source file name by doing format detection and returns a usable pointer
|
||||
/// to it, or NULL on failure.
|
||||
/// </summary>
|
||||
/// <param name="sourceFileName">Path to source file name.</param>
|
||||
/// <returns>Pointer to VGMSTREAM or NULL on failure.</returns>
|
||||
[DllImport(DllName, EntryPoint = "init_vgmstream", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern IntPtr Initialize(string sourceFileName);
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a VGMSTREAM from stream file by doing format detection and returns a usable pointer
|
||||
/// to it, or NULL on failure.
|
||||
/// </summary>
|
||||
/// <param name="streamFile">Pointer to stream file.</param>
|
||||
/// <returns>Pointer to VGMSTREAM or NULL on failure.</returns>
|
||||
[DllImport(DllName, EntryPoint = "init_from_STREAMFILE", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern IntPtr InitializeFromStreamFile(IntPtr streamFile);
|
||||
|
||||
/// <summary>
|
||||
/// Resets a VGMSTREAM to start of stream.
|
||||
/// </summary>
|
||||
/// <param name="vgmstream">Pointer to VGMSTREAM.</param>
|
||||
[DllImport(DllName, EntryPoint = "reset_vgmstream", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void Reset(IntPtr vgmstream);
|
||||
|
||||
/// <summary>
|
||||
/// Closes an open VGMSTREAM.
|
||||
/// </summary>
|
||||
/// <param name="vgmstream">Pointer to VGMSTREAM.</param>
|
||||
[DllImport(DllName, EntryPoint = "close_vgmstream", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void Close(IntPtr vgmstream);
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the number of samples to be played based on looping parameters.
|
||||
/// </summary>
|
||||
[DllImport(DllName, EntryPoint = "get_vgmstream_play_samples", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int GetPlaySamples(double loopTimes, double fadeSeconds, double fadeDelaySeconds, IntPtr vgmstream);
|
||||
|
||||
/// <summary>
|
||||
/// Renders VGMSTREAM to sample buffer.
|
||||
/// </summary>
|
||||
/// <param name="buffer">Destination sample buffer.</param>
|
||||
/// <param name="sampleCount">Amount of samples to render.</param>
|
||||
/// <param name="vgmstream">Pointer to VGMSTREAM.</param>
|
||||
[DllImport(DllName, EntryPoint = "render_vgmstream", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void Render(short[] buffer, int sampleCount, IntPtr vgmstream);
|
||||
|
||||
/// <summary>
|
||||
/// Renders VGMSTREAM to byte buffer.
|
||||
/// </summary>
|
||||
/// <param name="buffer">Destination byte buffer.</param>
|
||||
/// <param name="sampleCount">Amount of samples to render.</param>
|
||||
/// <param name="vgmstream">Pointer to VGMSTREAM.</param>
|
||||
[DllImport(DllName, EntryPoint = "render_vgmstream", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void Render8(byte[] buffer, int sampleCount, IntPtr vgmstream);
|
||||
|
||||
/// <summary>
|
||||
/// Writes a description of the stream into array pointed by description,
|
||||
/// which must be length bytes long. Will always be null-terminated if length > 0
|
||||
/// </summary>
|
||||
[DllImport(DllName, EntryPoint = "describe_vgmstream", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void Describe(IntPtr vgmstream, IntPtr description, int length);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the average bitrate in bps of all unique files contained within
|
||||
/// this stream. Compares files by absolute paths.
|
||||
/// </summary>
|
||||
/// <param name="vgmstream">Pointer to VGMSTREAM.</param>
|
||||
[DllImport(DllName, EntryPoint = "get_vgmstream_average_bitrate", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int GetAverageBitrate(IntPtr vgmstream);
|
||||
|
||||
/// <summary>
|
||||
/// Allocates a VGMSTREAM.
|
||||
/// </summary>
|
||||
[DllImport(DllName, EntryPoint = "allocate_vgmstream", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern IntPtr Allocate(int channelCount, [MarshalAs(UnmanagedType.I4)]bool looped);
|
||||
|
||||
/// <summary>
|
||||
/// smallest self-contained group of samples is a frame
|
||||
/// </summary>
|
||||
[DllImport(DllName, EntryPoint = "get_vgmstream_samples_per_frame", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int GetSamplesPerFrame(IntPtr vgmstream);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of bytes per frame.
|
||||
/// </summary>
|
||||
[DllImport(DllName, EntryPoint = "get_vgmstream_frame_size", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int GetFrameSize(IntPtr vgmstream);
|
||||
|
||||
/// <summary>
|
||||
/// in NDS IMA the frame size is the block size, so the last one is short
|
||||
/// </summary>
|
||||
[DllImport(DllName, EntryPoint = "get_vgmstream_samples_per_shortframe", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int GetSamplesPerShortframe(IntPtr vgmstream);
|
||||
|
||||
[DllImport(DllName, EntryPoint = "get_vgmstream_shortframe_size", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int GetShortframeSize(IntPtr vgmstream);
|
||||
|
||||
/// <summary>
|
||||
/// Assumes that we have written samplesWrittem into the buffer already, and we have samplesToDo consecutive
|
||||
/// samples ahead of us. Decode those samples into the buffer.
|
||||
/// </summary>
|
||||
[DllImport(DllName, EntryPoint = "decode_vgmstream", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void Decode(IntPtr vgmstream, int samplesWritten, int samplesToDo, short[] buffer);
|
||||
|
||||
/// <summary>
|
||||
/// Assumes additionally that we have samplesToDo consecutive samples in "data",
|
||||
/// and this this is for channel number "channel".
|
||||
/// </summary>
|
||||
[DllImport(DllName, EntryPoint = "decode_vgmstream_mem", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void DecodeMem(IntPtr vgmstream, int samplesWritten, int samplesToDo, short[] buffer, byte[] data, int channel);
|
||||
|
||||
/// <summary>
|
||||
/// Calculates number of consecutive samples to do (taking into account stopping for loop start and end.)
|
||||
/// </summary>
|
||||
[DllImport(DllName, EntryPoint = "vgmstream_samples_to_do", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int SamplesToDo(int samplesThisBlock, int samplesPerFrame, IntPtr vgmstream);
|
||||
|
||||
/// <summary>
|
||||
/// Detects start and save values, also detects end and restore values. Only works on exact sample values.
|
||||
/// </summary>
|
||||
[DllImport(DllName, EntryPoint = "vgmstream_do_loop", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int DoLoop(IntPtr vgmstream);
|
||||
|
||||
/// <summary>
|
||||
/// Opens a stream for reading at offset (standarized taking into account layouts, channels and so on.)
|
||||
/// returns 0 on failure
|
||||
/// </summary>
|
||||
[DllImport(DllName, EntryPoint = "vgmstream_open_stream", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int OpenStream(IntPtr vgmstream, IntPtr streamFile, long position);
|
||||
#endregion
|
||||
|
||||
#region Format Exports
|
||||
/// <summary>
|
||||
/// Gets a pointer to the array of supported formats.
|
||||
/// </summary>
|
||||
[DllImport(DllName, EntryPoint = "vgmstream_get_formats", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern IntPtr GetFormatsPtr();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the length of the format array.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[DllImport(DllName, EntryPoint = "vgmstream_get_formats_length", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int GetFormatsLength();
|
||||
|
||||
[DllImport(DllName, EntryPoint = "get_vgmstream_coding_description", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern string GetCodingDescription(int codingEnumCode);
|
||||
|
||||
[DllImport(DllName, EntryPoint = "get_vgmstream_layout_description", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern string GetLayoutDescription(int layoutEnumCode);
|
||||
|
||||
[DllImport(DllName, EntryPoint = "get_vgmstream_meta_description", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern string GetMetaDescription(int metaEnumCode);
|
||||
#endregion
|
||||
|
||||
#region Helper Methods
|
||||
/// <summary>
|
||||
/// Gets the sample count of a VGMSTREAM.
|
||||
/// </summary>
|
||||
/// <param name="vgmstream">Pointer to VGMSTREAM.</param>
|
||||
public static int GetSampleCount(IntPtr vgmstream)
|
||||
{
|
||||
return Marshal.ReadInt32(vgmstream);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sample rate of a VGMSTREAM.
|
||||
/// </summary>
|
||||
/// <param name="vgmstream">Pointer to VGMSTREAM.</param>
|
||||
public static int GetSampleRate(IntPtr vgmstream)
|
||||
{
|
||||
return Marshal.ReadInt32(vgmstream, 4);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the channel count of a VGMSTREAM.
|
||||
/// </summary>
|
||||
/// <param name="vgmstream">Pointer to VGMSTREAM.</param>
|
||||
public static int GetChannelCount(IntPtr vgmstream)
|
||||
{
|
||||
return Marshal.ReadInt32(vgmstream, 8);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the absolute sample count of a VGMSTREAM.
|
||||
/// (sample count * channel count)
|
||||
/// </summary>
|
||||
/// <param name="vgmstream">Pointer to VGMSTREAM.</param>
|
||||
public static int GetAbsoluteSampleCount(IntPtr vgmstream)
|
||||
{
|
||||
return GetSampleCount(vgmstream) * GetChannelCount(vgmstream);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the loop flag of a VGMSTREAM.
|
||||
/// </summary>
|
||||
/// <param name="vgmstream">Pointer to VGMSTREAM.</param>
|
||||
public static bool GetLoopFlag(IntPtr vgmstream)
|
||||
{
|
||||
return Marshal.ReadInt32(vgmstream, 28) != 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the loop flag of a VGMSTREAM.
|
||||
/// </summary>
|
||||
/// <param name="vgmstream">Pointer to VGMSTREAM.</param>
|
||||
public static void SetLoopFlag(IntPtr vgmstream, bool value)
|
||||
{
|
||||
if (value && !GetLoopFlag(vgmstream))
|
||||
{
|
||||
Marshal.WriteIntPtr(vgmstream, 48, Marshal.AllocHGlobal(GetChannelCount(vgmstream) * SizeOfVgmStreamChannel));
|
||||
}
|
||||
|
||||
Marshal.WriteInt32(vgmstream, 28, value ? 1 : 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the loop start sample of a VGMSTREAM.
|
||||
/// </summary>
|
||||
/// <param name="vgmstream">Pointer to VGMSTREAM.</param>
|
||||
public static int GetLoopStartSample(IntPtr vgmstream)
|
||||
{
|
||||
return Marshal.ReadInt32(vgmstream, 32);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the loop start sample of a VGMSTREAM.
|
||||
/// </summary>
|
||||
/// <param name="vgmstream">Pointer to VGMSTREAM.</param>
|
||||
public static void SetLoopStartSample(IntPtr vgmstream, int value)
|
||||
{
|
||||
Marshal.WriteInt32(vgmstream, 32, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the loop end sample of a VGMSTREAM.
|
||||
/// </summary>
|
||||
/// <param name="vgmstream">Pointer to VGMSTREAM.</param>
|
||||
public static int GetLoopEndSample(IntPtr vgmstream)
|
||||
{
|
||||
return Marshal.ReadInt32(vgmstream, 36);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the loop end sample of a VGMSTREAM.
|
||||
/// </summary>
|
||||
/// <param name="vgmstream">Pointer to VGMSTREAM.</param>
|
||||
public static void SetLoopEndSample(IntPtr vgmstream, int value)
|
||||
{
|
||||
Marshal.WriteInt32(vgmstream, 36, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current sample of a VGMSTREAM.
|
||||
/// </summary>
|
||||
/// <param name="vgmstream">Pointer to VGMSTREAM.</param>
|
||||
public static int GetCurrentSample(IntPtr vgmstream)
|
||||
{
|
||||
return Marshal.ReadInt32(vgmstream, 52);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an array of supported formats.
|
||||
/// </summary>
|
||||
/// <param name="vgmstream">Pointer to VGMSTREAM.</param>
|
||||
public static string[] GetFormats()
|
||||
{
|
||||
string[] formats = new string[GetFormatsLength()];
|
||||
|
||||
IntPtr ptr = GetFormatsPtr();
|
||||
for (int i = 0; i < formats.Length; i++)
|
||||
{
|
||||
IntPtr stringPtr = Marshal.ReadIntPtr(ptr, i * IntPtr.Size);
|
||||
formats[i] = Marshal.PtrToStringAnsi(stringPtr);
|
||||
}
|
||||
|
||||
return formats;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
282
Source/CsbBuilder/Audio/VGMStreamReader.cs
Normal file
282
Source/CsbBuilder/Audio/VGMStreamReader.cs
Normal file
@ -0,0 +1,282 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using NAudio.Wave;
|
||||
using NAudio.Wave.SampleProviders;
|
||||
|
||||
namespace CsbBuilder.Audio
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a NAudio WaveStream for VGMSTREAM playback.
|
||||
/// </summary>
|
||||
public class VGMStreamReader : WaveStream
|
||||
{
|
||||
private IntPtr vgmstream;
|
||||
private WaveFormat waveFormat;
|
||||
private int sampleCount;
|
||||
private bool loopFlag;
|
||||
|
||||
private byte[] cache;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the wave format of the VGMSTREAM.
|
||||
/// </summary>
|
||||
public override WaveFormat WaveFormat
|
||||
{
|
||||
get
|
||||
{
|
||||
return waveFormat;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the length of this VGMSTREAM in bytes.
|
||||
/// </summary>
|
||||
public override long Length
|
||||
{
|
||||
get
|
||||
{
|
||||
return sampleCount * waveFormat.Channels * 2;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the position of this VGMSTREAM in bytes.
|
||||
/// </summary>
|
||||
public override long Position
|
||||
{
|
||||
get
|
||||
{
|
||||
return VGMStreamNative.GetCurrentSample(vgmstream) * waveFormat.Channels * 2;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
CurrentSample = (int)(value / waveFormat.Channels / 2);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the current sample of this VGMSTREAM.
|
||||
/// </summary>
|
||||
public int CurrentSample
|
||||
{
|
||||
get
|
||||
{
|
||||
return VGMStreamNative.GetCurrentSample(vgmstream);
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
int currentSample = VGMStreamNative.GetCurrentSample(vgmstream);
|
||||
|
||||
if (value == currentSample || value > sampleCount)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (value > currentSample)
|
||||
{
|
||||
value = value - currentSample;
|
||||
}
|
||||
|
||||
else if (value < currentSample)
|
||||
{
|
||||
VGMStreamNative.Reset(vgmstream);
|
||||
}
|
||||
|
||||
int cacheSampleLength = cache.Length / waveFormat.Channels / 2;
|
||||
int length = 0;
|
||||
|
||||
while (length < value)
|
||||
{
|
||||
if (length + cacheSampleLength >= value)
|
||||
{
|
||||
cacheSampleLength = value - length;
|
||||
}
|
||||
|
||||
VGMStreamNative.Render8(cache, cacheSampleLength, vgmstream);
|
||||
length += cacheSampleLength;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the loop is enabled for the VGMSTREAM.
|
||||
/// </summary>
|
||||
public bool LoopFlag
|
||||
{
|
||||
get
|
||||
{
|
||||
return loopFlag;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the loop start sample of the VGMSTREAM.
|
||||
/// </summary>
|
||||
public long LoopStartSample
|
||||
{
|
||||
get
|
||||
{
|
||||
return VGMStreamNative.GetLoopStartSample(vgmstream);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the loop start position of the VGMSTREAM in bytes.
|
||||
/// </summary>
|
||||
public long LoopStartPosition
|
||||
{
|
||||
get
|
||||
{
|
||||
return LoopStartSample * waveFormat.Channels * 2;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the loop end sample of the VGMSTREAM.
|
||||
/// </summary>
|
||||
public long LoopEndSample
|
||||
{
|
||||
get
|
||||
{
|
||||
return VGMStreamNative.GetLoopEndSample(vgmstream);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the loop end position of the VGMSTREAM in bytes.
|
||||
/// </summary>
|
||||
public long LoopEndPosition
|
||||
{
|
||||
get
|
||||
{
|
||||
return LoopEndSample * waveFormat.Channels * 2;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Forces the VGMSTREAM to loop from start to end.
|
||||
/// This method destroys the previous loop points.
|
||||
/// </summary>
|
||||
public void ForceLoop()
|
||||
{
|
||||
VGMStreamNative.SetLoopFlag(vgmstream, true);
|
||||
VGMStreamNative.SetLoopStartSample(vgmstream, 0);
|
||||
VGMStreamNative.SetLoopEndSample(vgmstream, sampleCount);
|
||||
|
||||
loopFlag = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disables the loop for this VGMSTREAM.
|
||||
/// </summary>
|
||||
public void DisableLoop()
|
||||
{
|
||||
loopFlag = false;
|
||||
VGMStreamNative.SetLoopFlag(vgmstream, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the VGMSTREAM to beginning.
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
VGMStreamNative.Reset(vgmstream);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renders the VGMSTREAM to byte buffer.
|
||||
/// </summary>
|
||||
/// <param name="buffer">Destination byte buffer.</param>
|
||||
/// <param name="offset">Offset within buffer to write to.</param>
|
||||
/// <param name="count">Count of bytes to render.</param>
|
||||
/// <returns>Number of bytes read.</returns>
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (cache == null || cache.Length < buffer.Length)
|
||||
{
|
||||
cache = new byte[buffer.Length];
|
||||
}
|
||||
|
||||
int currentSample = VGMStreamNative.GetCurrentSample(vgmstream);
|
||||
int sampleCount_vgmstream = count / waveFormat.Channels / 2;
|
||||
|
||||
if (currentSample >= sampleCount && !loopFlag)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!loopFlag && currentSample + sampleCount_vgmstream > sampleCount)
|
||||
{
|
||||
sampleCount_vgmstream = sampleCount - currentSample;
|
||||
}
|
||||
|
||||
count = sampleCount_vgmstream * waveFormat.Channels * 2;
|
||||
|
||||
VGMStreamNative.Render8(cache, sampleCount_vgmstream, vgmstream);
|
||||
Array.Copy(cache, 0, buffer, offset, count);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
VGMStreamNative.Close(vgmstream);
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
private void FromPtr(IntPtr vgmstream)
|
||||
{
|
||||
if (vgmstream == IntPtr.Zero)
|
||||
{
|
||||
throw new NullReferenceException("VGMSTREAM pointer is set to null!");
|
||||
}
|
||||
|
||||
waveFormat = new WaveFormat(VGMStreamNative.GetSampleRate(vgmstream), 16, VGMStreamNative.GetChannelCount(vgmstream));
|
||||
sampleCount = VGMStreamNative.GetSampleCount(vgmstream);
|
||||
loopFlag = VGMStreamNative.GetLoopFlag(vgmstream);
|
||||
|
||||
cache = new byte[4096];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs from source file name.
|
||||
/// </summary>
|
||||
/// <param name="sourceFileName">Source file name to load.</param>
|
||||
public VGMStreamReader(string sourceFileName)
|
||||
{
|
||||
if (!File.Exists(sourceFileName))
|
||||
{
|
||||
throw new FileNotFoundException($"VGMStream could not find file: {sourceFileName}");
|
||||
}
|
||||
|
||||
vgmstream = VGMStreamNative.Initialize(sourceFileName);
|
||||
if (vgmstream == IntPtr.Zero)
|
||||
{
|
||||
throw new NullReferenceException($"VGMStream could not initialize file: {sourceFileName}");
|
||||
}
|
||||
|
||||
FromPtr(vgmstream);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs from pointer.
|
||||
/// </summary>
|
||||
/// <param name="vgmstream">Pointer to VGMSTREAM.</param>
|
||||
public VGMStreamReader(IntPtr vgmstream)
|
||||
{
|
||||
FromPtr(vgmstream);
|
||||
}
|
||||
}
|
||||
}
|
@ -5,12 +5,12 @@ using System.Text;
|
||||
using System.IO;
|
||||
|
||||
using CsbBuilder.Project;
|
||||
using CsbBuilder.BuilderNode;
|
||||
using CsbBuilder.BuilderNodes;
|
||||
using CsbBuilder.Serialization;
|
||||
|
||||
using SonicAudioLib.CriMw;
|
||||
using SonicAudioLib.CriMw.Serialization;
|
||||
using SonicAudioLib.Archive;
|
||||
using SonicAudioLib.Archives;
|
||||
|
||||
namespace CsbBuilder.Builder
|
||||
{
|
||||
@ -192,6 +192,8 @@ namespace CsbBuilder.Builder
|
||||
Flag = CriAaxEntryFlag.Intro,
|
||||
FilePath = new FileInfo(Path.Combine(project.AudioDirectory.FullName, soundElementNode.Intro)),
|
||||
});
|
||||
|
||||
aaxArchive.SetModeFromExtension(soundElementNode.Intro);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(soundElementNode.Loop))
|
||||
@ -201,6 +203,8 @@ namespace CsbBuilder.Builder
|
||||
Flag = CriAaxEntryFlag.Loop,
|
||||
FilePath = new FileInfo(Path.Combine(project.AudioDirectory.FullName, soundElementNode.Loop)),
|
||||
});
|
||||
|
||||
aaxArchive.SetModeFromExtension(soundElementNode.Loop);
|
||||
}
|
||||
|
||||
byte[] data = new byte[0];
|
||||
@ -228,7 +232,7 @@ namespace CsbBuilder.Builder
|
||||
{
|
||||
Name = soundElementNode.Name,
|
||||
Data = data,
|
||||
FormatType = 0,
|
||||
FormatType = (byte)aaxArchive.Mode,
|
||||
SoundFrequency = soundElementNode.SampleRate,
|
||||
NumberChannels = soundElementNode.ChannelCount,
|
||||
Streaming = soundElementNode.Streaming,
|
||||
|
@ -5,7 +5,7 @@ using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace CsbBuilder.BuilderNode
|
||||
namespace CsbBuilder.BuilderNodes
|
||||
{
|
||||
public class BuilderAisacGraphNode : BuilderBaseNode
|
||||
{
|
@ -5,7 +5,7 @@ using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace CsbBuilder.BuilderNode
|
||||
namespace CsbBuilder.BuilderNodes
|
||||
{
|
||||
public class BuilderAisacNode : BuilderBaseNode
|
||||
{
|
@ -5,7 +5,7 @@ using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace CsbBuilder.BuilderNode
|
||||
namespace CsbBuilder.BuilderNodes
|
||||
{
|
||||
public class BuilderAisacPointNode : BuilderBaseNode
|
||||
{
|
@ -6,12 +6,12 @@ using System.Threading.Tasks;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
|
||||
namespace CsbBuilder.BuilderNode
|
||||
namespace CsbBuilder.BuilderNodes
|
||||
{
|
||||
public abstract class BuilderBaseNode : ICloneable
|
||||
{
|
||||
[Category("General"), ReadOnly(true)]
|
||||
[Description("The name of this node. Shift JIS encoding is used for this in the Cue Sheet Binary, so try to avoid using special characters that this codec does not support.")]
|
||||
[Description("The name of this node.")]
|
||||
public string Name { get; set; }
|
||||
|
||||
public object Clone()
|
@ -5,7 +5,7 @@ using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace CsbBuilder.BuilderNode
|
||||
namespace CsbBuilder.BuilderNodes
|
||||
{
|
||||
public class BuilderCueNode : BuilderBaseNode
|
||||
{
|
||||
@ -19,7 +19,7 @@ namespace CsbBuilder.BuilderNode
|
||||
public string SynthReference { get; set; }
|
||||
|
||||
[Category("General"), DisplayName("User Comment")]
|
||||
[Description("User comment of this Cue. Shift JIS encoding is used for this in the Cue Sheet Binary, so try to avoid using special characters that this codec does not support.")]
|
||||
[Description("User comment of this Cue.")]
|
||||
public string UserComment { get; set; }
|
||||
|
||||
[Category("General")]
|
@ -5,7 +5,7 @@ using System.Text;
|
||||
using System.IO;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace CsbBuilder.BuilderNode
|
||||
namespace CsbBuilder.BuilderNodes
|
||||
{
|
||||
public class BuilderSoundElementNode : BuilderBaseNode
|
||||
{
|
@ -6,7 +6,7 @@ using System.Threading.Tasks;
|
||||
using System.ComponentModel;
|
||||
using System.Reflection;
|
||||
|
||||
namespace CsbBuilder.BuilderNode
|
||||
namespace CsbBuilder.BuilderNodes
|
||||
{
|
||||
public enum BuilderSynthType
|
||||
{
|
||||
@ -28,7 +28,7 @@ namespace CsbBuilder.BuilderNode
|
||||
{
|
||||
private BuilderSynthPlaybackType playbackType = BuilderSynthPlaybackType.Polyphonic;
|
||||
private Random random = new Random();
|
||||
private List<int> indices = new List<int>();
|
||||
private int previousChild = -1;
|
||||
private int nextChild = -1;
|
||||
private byte playbackProbability = 100;
|
||||
|
||||
@ -362,20 +362,15 @@ namespace CsbBuilder.BuilderNode
|
||||
{
|
||||
if (playbackType == BuilderSynthPlaybackType.RandomNoRepeat)
|
||||
{
|
||||
if (indices.Count == Children.Count)
|
||||
int randomChild = random.Next(Children.Count);
|
||||
|
||||
while (randomChild == previousChild)
|
||||
{
|
||||
indices.Clear();
|
||||
randomChild = random.Next(Children.Count);
|
||||
}
|
||||
|
||||
int nextChild = random.Next(Children.Count);
|
||||
|
||||
while (indices.Contains(nextChild))
|
||||
{
|
||||
nextChild = random.Next(Children.Count);
|
||||
}
|
||||
|
||||
indices.Add(nextChild);
|
||||
return nextChild;
|
||||
previousChild = randomChild;
|
||||
return randomChild;
|
||||
}
|
||||
|
||||
return random.Next(Children.Count);
|
@ -5,7 +5,7 @@ using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace CsbBuilder.BuilderNode
|
||||
namespace CsbBuilder.BuilderNodes
|
||||
{
|
||||
public class BuilderVoiceLimitGroupNode : BuilderBaseNode
|
||||
{
|
@ -9,9 +9,10 @@
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>CsbBuilder</RootNamespace>
|
||||
<AssemblyName>CsbBuilder</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
@ -22,6 +23,7 @@
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
@ -53,15 +55,18 @@
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Audio\AdxFileReader.cs" />
|
||||
<Compile Include="BuilderNode\BuilderAisacGraphNode.cs" />
|
||||
<Compile Include="BuilderNode\BuilderAisacNode.cs" />
|
||||
<Compile Include="BuilderNode\BuilderAisacPointNode.cs" />
|
||||
<Compile Include="BuilderNode\BuilderCueNode.cs" />
|
||||
<Compile Include="BuilderNode\BuilderBaseNode.cs" />
|
||||
<Compile Include="BuilderNode\BuilderSoundElementNode.cs" />
|
||||
<Compile Include="BuilderNode\BuilderSynthNode.cs" />
|
||||
<Compile Include="BuilderNode\BuilderVoiceLimitGroupNode.cs" />
|
||||
<Compile Include="Audio\ExtendedWaveStream.cs" />
|
||||
<Compile Include="Audio\PostSampleEditor.cs" />
|
||||
<Compile Include="Audio\VGMStreamNative.cs" />
|
||||
<Compile Include="Audio\VGMStreamReader.cs" />
|
||||
<Compile Include="BuilderNodes\BuilderAisacGraphNode.cs" />
|
||||
<Compile Include="BuilderNodes\BuilderAisacNode.cs" />
|
||||
<Compile Include="BuilderNodes\BuilderAisacPointNode.cs" />
|
||||
<Compile Include="BuilderNodes\BuilderCueNode.cs" />
|
||||
<Compile Include="BuilderNodes\BuilderBaseNode.cs" />
|
||||
<Compile Include="BuilderNodes\BuilderSoundElementNode.cs" />
|
||||
<Compile Include="BuilderNodes\BuilderSynthNode.cs" />
|
||||
<Compile Include="BuilderNodes\BuilderVoiceLimitGroupNode.cs" />
|
||||
<Compile Include="Builder\CsbBuilder.cs" />
|
||||
<Compile Include="ExceptionForm.cs">
|
||||
<SubType>Form</SubType>
|
||||
@ -228,7 +233,11 @@
|
||||
<None Include="Resources\Undo_grey_16x.png" />
|
||||
<None Include="Resources\Settings_16x.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
<PostBuildEvent>copy "$(SolutionDir)Libraries\*.dll" "$(TargetDir)"</PostBuildEvent>
|
||||
</PropertyGroup>
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
|
@ -7,12 +7,12 @@ using System.ComponentModel;
|
||||
|
||||
using CsbBuilder.Audio;
|
||||
using CsbBuilder.Project;
|
||||
using CsbBuilder.BuilderNode;
|
||||
using CsbBuilder.BuilderNodes;
|
||||
using CsbBuilder.Serialization;
|
||||
|
||||
using SonicAudioLib.IO;
|
||||
using SonicAudioLib.CriMw.Serialization;
|
||||
using SonicAudioLib.Archive;
|
||||
using SonicAudioLib.Archives;
|
||||
|
||||
using System.Windows.Forms;
|
||||
|
||||
@ -25,7 +25,7 @@ namespace CsbBuilder.Importer
|
||||
var extractor = new DataExtractor();
|
||||
extractor.BufferSize = MainForm.Settings.BufferSize;
|
||||
extractor.EnableThreading = MainForm.Settings.EnableThreading;
|
||||
extractor.MaxThreads = MainForm.Settings.MaxCores;
|
||||
extractor.MaxThreads = MainForm.Settings.MaxThreads;
|
||||
|
||||
// Find the CPK first
|
||||
string cpkPath = Path.ChangeExtension(path, "cpk");
|
||||
@ -50,7 +50,7 @@ namespace CsbBuilder.Importer
|
||||
List<SerializationSynthTable> synthTables = CriTableSerializer.Deserialize<SerializationSynthTable>(cueSheets.FirstOrDefault(table => table.TableType == 2).TableData);
|
||||
List<SerializationSoundElementTable> soundElementTables = CriTableSerializer.Deserialize<SerializationSoundElementTable>(cueSheets.FirstOrDefault(table => table.TableType == 4).TableData);
|
||||
List<SerializationAisacTable> aisacTables = CriTableSerializer.Deserialize<SerializationAisacTable>(cueSheets.FirstOrDefault(table => table.TableType == 5).TableData);
|
||||
|
||||
|
||||
// voice limit groups appeared in the later versions, so check if it exists.
|
||||
List<SerializationVoiceLimitGroupTable> voiceLimitGroupTables = new List<SerializationVoiceLimitGroupTable>();
|
||||
|
||||
@ -83,16 +83,22 @@ namespace CsbBuilder.Importer
|
||||
|
||||
CriAaxArchive aaxArchive = new CriAaxArchive();
|
||||
|
||||
CriCpkEntry cpkEntry = null;
|
||||
if (soundElementNode.Streaming)
|
||||
CriCpkEntry cpkEntry = cpkArchive.GetByPath(soundElementTable.Name);
|
||||
if (soundElementNode.Streaming && cpkEntry != null)
|
||||
{
|
||||
using (Stream source = File.OpenRead(cpkPath))
|
||||
using (Stream entrySource = (cpkEntry = cpkArchive.GetByPath(soundElementTable.Name)).Open(source))
|
||||
using (Stream entrySource = cpkEntry.Open(source))
|
||||
{
|
||||
aaxArchive.Read(entrySource);
|
||||
}
|
||||
}
|
||||
|
||||
else if (soundElementNode.Streaming && cpkEntry == null)
|
||||
{
|
||||
soundElementNode.Intro = soundElementNode.Loop = string.Empty;
|
||||
soundElementNode.SampleRate = soundElementNode.SampleCount = soundElementNode.ChannelCount = 0;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
aaxArchive.Load(soundElementTable.Data);
|
||||
@ -103,13 +109,13 @@ namespace CsbBuilder.Importer
|
||||
string outputFileName = Path.Combine(project.AudioDirectory.FullName, soundElementTable.Name.Replace('/', '_'));
|
||||
if (entry.Flag == CriAaxEntryFlag.Intro)
|
||||
{
|
||||
outputFileName += "_Intro.adx";
|
||||
outputFileName += $"_Intro{aaxArchive.GetModeExtension()}";
|
||||
soundElementNode.Intro = Path.GetFileName(outputFileName);
|
||||
}
|
||||
|
||||
else if (entry.Flag == CriAaxEntryFlag.Loop)
|
||||
{
|
||||
outputFileName += "_Loop.adx";
|
||||
outputFileName += $"_Loop{aaxArchive.GetModeExtension()}";
|
||||
soundElementNode.Loop = Path.GetFileName(outputFileName);
|
||||
}
|
||||
|
||||
|
178
Source/CsbBuilder/MainForm.Designer.cs
generated
178
Source/CsbBuilder/MainForm.Designer.cs
generated
@ -46,11 +46,11 @@
|
||||
this.buildCurrentProjectAsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripMenuItem49 = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.aDXToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.convertADXsToWAVToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.aAXToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.extractAAXToFolderToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.packFolderToAAXToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.convertADXsToWAVToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.convertAndSplitLoopingToWAVToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripSeparator26 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.settingsButton = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.aboutToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
@ -182,6 +182,7 @@
|
||||
this.toolStripMenuItem41 = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripMenuItem42 = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripMenuItem43 = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripSeparator27 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.mainMenu.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit();
|
||||
this.splitContainer1.Panel1.SuspendLayout();
|
||||
@ -375,42 +376,29 @@
|
||||
this.toolStripSeparator26,
|
||||
this.settingsButton});
|
||||
this.toolsToolStripMenuItem.Name = "toolsToolStripMenuItem";
|
||||
this.toolsToolStripMenuItem.Size = new System.Drawing.Size(48, 20);
|
||||
this.toolsToolStripMenuItem.Size = new System.Drawing.Size(47, 20);
|
||||
this.toolsToolStripMenuItem.Text = "Tools";
|
||||
//
|
||||
// toolStripMenuItem49
|
||||
//
|
||||
this.toolStripMenuItem49.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.aDXToolStripMenuItem,
|
||||
this.convertADXsToWAVToolStripMenuItem,
|
||||
this.convertAndSplitLoopingToWAVToolStripMenuItem,
|
||||
this.toolStripSeparator27,
|
||||
this.aAXToolStripMenuItem});
|
||||
this.toolStripMenuItem49.Image = global::CsbBuilder.Properties.Resources.Sound;
|
||||
this.toolStripMenuItem49.Name = "toolStripMenuItem49";
|
||||
this.toolStripMenuItem49.Size = new System.Drawing.Size(138, 22);
|
||||
this.toolStripMenuItem49.Size = new System.Drawing.Size(152, 22);
|
||||
this.toolStripMenuItem49.Text = "Audio Tools";
|
||||
//
|
||||
// aDXToolStripMenuItem
|
||||
//
|
||||
this.aDXToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.convertADXsToWAVToolStripMenuItem});
|
||||
this.aDXToolStripMenuItem.Name = "aDXToolStripMenuItem";
|
||||
this.aDXToolStripMenuItem.Size = new System.Drawing.Size(97, 22);
|
||||
this.aDXToolStripMenuItem.Text = "ADX";
|
||||
//
|
||||
// convertADXsToWAVToolStripMenuItem
|
||||
//
|
||||
this.convertADXsToWAVToolStripMenuItem.Name = "convertADXsToWAVToolStripMenuItem";
|
||||
this.convertADXsToWAVToolStripMenuItem.Size = new System.Drawing.Size(198, 22);
|
||||
this.convertADXsToWAVToolStripMenuItem.Text = "Convert ADX(s) to WAV";
|
||||
this.convertADXsToWAVToolStripMenuItem.Click += new System.EventHandler(this.convertADXsToWAVToolStripMenuItem_Click);
|
||||
//
|
||||
// aAXToolStripMenuItem
|
||||
//
|
||||
this.aAXToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.extractAAXToFolderToolStripMenuItem,
|
||||
this.packFolderToAAXToolStripMenuItem});
|
||||
this.aAXToolStripMenuItem.Name = "aAXToolStripMenuItem";
|
||||
this.aAXToolStripMenuItem.Size = new System.Drawing.Size(97, 22);
|
||||
this.aAXToolStripMenuItem.Text = "AAX";
|
||||
this.aAXToolStripMenuItem.Size = new System.Drawing.Size(240, 22);
|
||||
this.aAXToolStripMenuItem.Text = "AAX Archive";
|
||||
//
|
||||
// extractAAXToFolderToolStripMenuItem
|
||||
//
|
||||
@ -423,19 +411,36 @@
|
||||
//
|
||||
this.packFolderToAAXToolStripMenuItem.Name = "packFolderToAAXToolStripMenuItem";
|
||||
this.packFolderToAAXToolStripMenuItem.Size = new System.Drawing.Size(196, 22);
|
||||
this.packFolderToAAXToolStripMenuItem.Text = "Pack ADX(s) to AAX";
|
||||
this.packFolderToAAXToolStripMenuItem.Text = "Pack file(s) to AAX";
|
||||
this.packFolderToAAXToolStripMenuItem.Click += new System.EventHandler(this.packFolderToAAXToolStripMenuItem_Click);
|
||||
//
|
||||
// convertADXsToWAVToolStripMenuItem
|
||||
//
|
||||
this.convertADXsToWAVToolStripMenuItem.Name = "convertADXsToWAVToolStripMenuItem";
|
||||
this.convertADXsToWAVToolStripMenuItem.Size = new System.Drawing.Size(240, 22);
|
||||
this.convertADXsToWAVToolStripMenuItem.Text = "Convert to WAV File(s)";
|
||||
this.convertADXsToWAVToolStripMenuItem.ToolTipText = "Convert audio files to WAV files";
|
||||
this.convertADXsToWAVToolStripMenuItem.Click += new System.EventHandler(this.convertADXsToWAVToolStripMenuItem_Click);
|
||||
//
|
||||
// convertAndSplitLoopingToWAVToolStripMenuItem
|
||||
//
|
||||
this.convertAndSplitLoopingToWAVToolStripMenuItem.Name = "convertAndSplitLoopingToWAVToolStripMenuItem";
|
||||
this.convertAndSplitLoopingToWAVToolStripMenuItem.Size = new System.Drawing.Size(240, 22);
|
||||
this.convertAndSplitLoopingToWAVToolStripMenuItem.Text = "Convert and split to WAV File(s)";
|
||||
this.convertAndSplitLoopingToWAVToolStripMenuItem.ToolTipText = "Convert and split audio files to Intro and Loop parts using loop information in t" +
|
||||
"he file";
|
||||
this.convertAndSplitLoopingToWAVToolStripMenuItem.Click += new System.EventHandler(this.convertAndSplitLoopingToWAVToolStripMenuItem_Click);
|
||||
//
|
||||
// toolStripSeparator26
|
||||
//
|
||||
this.toolStripSeparator26.Name = "toolStripSeparator26";
|
||||
this.toolStripSeparator26.Size = new System.Drawing.Size(135, 6);
|
||||
this.toolStripSeparator26.Size = new System.Drawing.Size(149, 6);
|
||||
//
|
||||
// settingsButton
|
||||
//
|
||||
this.settingsButton.Image = global::CsbBuilder.Properties.Resources.Settings;
|
||||
this.settingsButton.Name = "settingsButton";
|
||||
this.settingsButton.Size = new System.Drawing.Size(138, 22);
|
||||
this.settingsButton.Size = new System.Drawing.Size(152, 22);
|
||||
this.settingsButton.Text = "Settings";
|
||||
this.settingsButton.Click += new System.EventHandler(this.OpenSettings);
|
||||
//
|
||||
@ -453,6 +458,7 @@
|
||||
| System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.propertyGrid.Enabled = false;
|
||||
this.propertyGrid.LineColor = System.Drawing.SystemColors.ControlDark;
|
||||
this.propertyGrid.Location = new System.Drawing.Point(252, 24);
|
||||
this.propertyGrid.Name = "propertyGrid";
|
||||
this.propertyGrid.Size = new System.Drawing.Size(374, 556);
|
||||
@ -498,7 +504,7 @@
|
||||
this.tabPage3.Padding = new System.Windows.Forms.Padding(3);
|
||||
this.tabPage3.Size = new System.Drawing.Size(242, 221);
|
||||
this.tabPage3.TabIndex = 0;
|
||||
this.tabPage3.Text = "Cue";
|
||||
this.tabPage3.Text = "Cue Nodes";
|
||||
this.tabPage3.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// cueTree
|
||||
@ -580,7 +586,7 @@
|
||||
this.tabPage4.Padding = new System.Windows.Forms.Padding(3);
|
||||
this.tabPage4.Size = new System.Drawing.Size(242, 279);
|
||||
this.tabPage4.TabIndex = 0;
|
||||
this.tabPage4.Text = "Synth";
|
||||
this.tabPage4.Text = "Synth Nodes";
|
||||
this.tabPage4.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// synthTree
|
||||
@ -739,7 +745,7 @@
|
||||
this.tabPage5.Padding = new System.Windows.Forms.Padding(3);
|
||||
this.tabPage5.Size = new System.Drawing.Size(242, 221);
|
||||
this.tabPage5.TabIndex = 0;
|
||||
this.tabPage5.Text = "Sound Element";
|
||||
this.tabPage5.Text = "Sound Element Nodes";
|
||||
this.tabPage5.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// soundElementTree
|
||||
@ -783,7 +789,7 @@
|
||||
this.tabPage1.Padding = new System.Windows.Forms.Padding(3);
|
||||
this.tabPage1.Size = new System.Drawing.Size(242, 279);
|
||||
this.tabPage1.TabIndex = 0;
|
||||
this.tabPage1.Text = "AISAC";
|
||||
this.tabPage1.Text = "AISAC Nodes";
|
||||
this.tabPage1.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// aisacTree
|
||||
@ -819,13 +825,13 @@
|
||||
this.toolStripMenuItem47});
|
||||
this.aisacTreeMenu.Name = "contextMenuStrip1";
|
||||
this.aisacTreeMenu.RenderMode = System.Windows.Forms.ToolStripRenderMode.System;
|
||||
this.aisacTreeMenu.Size = new System.Drawing.Size(190, 104);
|
||||
this.aisacTreeMenu.Size = new System.Drawing.Size(189, 104);
|
||||
//
|
||||
// toolStripMenuItem45
|
||||
//
|
||||
this.toolStripMenuItem45.Image = global::CsbBuilder.Properties.Resources.Create;
|
||||
this.toolStripMenuItem45.Name = "toolStripMenuItem45";
|
||||
this.toolStripMenuItem45.Size = new System.Drawing.Size(189, 22);
|
||||
this.toolStripMenuItem45.Size = new System.Drawing.Size(188, 22);
|
||||
this.toolStripMenuItem45.Text = "Create";
|
||||
this.toolStripMenuItem45.ToolTipText = "Create a new node.";
|
||||
this.toolStripMenuItem45.Click += new System.EventHandler(this.CreateNode);
|
||||
@ -834,7 +840,7 @@
|
||||
//
|
||||
this.toolStripMenuItem46.Image = global::CsbBuilder.Properties.Resources.Folder;
|
||||
this.toolStripMenuItem46.Name = "toolStripMenuItem46";
|
||||
this.toolStripMenuItem46.Size = new System.Drawing.Size(189, 22);
|
||||
this.toolStripMenuItem46.Size = new System.Drawing.Size(188, 22);
|
||||
this.toolStripMenuItem46.Text = "Create Folder";
|
||||
this.toolStripMenuItem46.ToolTipText = "Create a new folder.";
|
||||
this.toolStripMenuItem46.Click += new System.EventHandler(this.CreateFolder);
|
||||
@ -842,26 +848,26 @@
|
||||
// toolStripSeparator24
|
||||
//
|
||||
this.toolStripSeparator24.Name = "toolStripSeparator24";
|
||||
this.toolStripSeparator24.Size = new System.Drawing.Size(186, 6);
|
||||
this.toolStripSeparator24.Size = new System.Drawing.Size(185, 6);
|
||||
//
|
||||
// toolStripMenuItem48
|
||||
//
|
||||
this.toolStripMenuItem48.Image = global::CsbBuilder.Properties.Resources.Template;
|
||||
this.toolStripMenuItem48.Name = "toolStripMenuItem48";
|
||||
this.toolStripMenuItem48.Size = new System.Drawing.Size(189, 22);
|
||||
this.toolStripMenuItem48.Size = new System.Drawing.Size(188, 22);
|
||||
this.toolStripMenuItem48.Text = "Load AISAC Template";
|
||||
this.toolStripMenuItem48.Click += new System.EventHandler(this.LoadTemplate);
|
||||
//
|
||||
// toolStripSeparator25
|
||||
//
|
||||
this.toolStripSeparator25.Name = "toolStripSeparator25";
|
||||
this.toolStripSeparator25.Size = new System.Drawing.Size(186, 6);
|
||||
this.toolStripSeparator25.Size = new System.Drawing.Size(185, 6);
|
||||
//
|
||||
// toolStripMenuItem47
|
||||
//
|
||||
this.toolStripMenuItem47.Image = global::CsbBuilder.Properties.Resources.Paste;
|
||||
this.toolStripMenuItem47.Name = "toolStripMenuItem47";
|
||||
this.toolStripMenuItem47.Size = new System.Drawing.Size(189, 22);
|
||||
this.toolStripMenuItem47.Size = new System.Drawing.Size(188, 22);
|
||||
this.toolStripMenuItem47.Text = "Paste";
|
||||
this.toolStripMenuItem47.ToolTipText = "Paste the copied node.";
|
||||
this.toolStripMenuItem47.Click += new System.EventHandler(this.PasteNodeOnTree);
|
||||
@ -874,7 +880,7 @@
|
||||
this.tabPage2.Padding = new System.Windows.Forms.Padding(3);
|
||||
this.tabPage2.Size = new System.Drawing.Size(242, 279);
|
||||
this.tabPage2.TabIndex = 1;
|
||||
this.tabPage2.Text = "Voice Limit Group";
|
||||
this.tabPage2.Text = "Voice Limit Group Nodes";
|
||||
this.tabPage2.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// voiceLimitGroupTree
|
||||
@ -1032,13 +1038,13 @@
|
||||
this.setVoiceLimitGroupReferenceToolStripMenuItem});
|
||||
this.trackMenu.Name = "cueAndVoiceLimitGroupMenu";
|
||||
this.trackMenu.RenderMode = System.Windows.Forms.ToolStripRenderMode.System;
|
||||
this.trackMenu.Size = new System.Drawing.Size(259, 220);
|
||||
this.trackMenu.Size = new System.Drawing.Size(258, 220);
|
||||
//
|
||||
// toolStripMenuItem16
|
||||
//
|
||||
this.toolStripMenuItem16.Image = global::CsbBuilder.Properties.Resources.Create;
|
||||
this.toolStripMenuItem16.Name = "toolStripMenuItem16";
|
||||
this.toolStripMenuItem16.Size = new System.Drawing.Size(258, 22);
|
||||
this.toolStripMenuItem16.Size = new System.Drawing.Size(257, 22);
|
||||
this.toolStripMenuItem16.Text = "Create Block";
|
||||
this.toolStripMenuItem16.ToolTipText = "Create a new child block node.";
|
||||
this.toolStripMenuItem16.Click += new System.EventHandler(this.CreateChildTrackNode);
|
||||
@ -1047,7 +1053,7 @@
|
||||
//
|
||||
this.createToolStripMenuItem3.Image = global::CsbBuilder.Properties.Resources.Sound;
|
||||
this.createToolStripMenuItem3.Name = "createToolStripMenuItem3";
|
||||
this.createToolStripMenuItem3.Size = new System.Drawing.Size(258, 22);
|
||||
this.createToolStripMenuItem3.Size = new System.Drawing.Size(257, 22);
|
||||
this.createToolStripMenuItem3.Text = "Create Sound";
|
||||
this.createToolStripMenuItem3.ToolTipText = "Create a new child sound node.";
|
||||
this.createToolStripMenuItem3.Click += new System.EventHandler(this.CreateChildNode);
|
||||
@ -1055,13 +1061,13 @@
|
||||
// toolStripSeparator10
|
||||
//
|
||||
this.toolStripSeparator10.Name = "toolStripSeparator10";
|
||||
this.toolStripSeparator10.Size = new System.Drawing.Size(255, 6);
|
||||
this.toolStripSeparator10.Size = new System.Drawing.Size(254, 6);
|
||||
//
|
||||
// toolStripMenuItem20
|
||||
//
|
||||
this.toolStripMenuItem20.Image = global::CsbBuilder.Properties.Resources.Copy;
|
||||
this.toolStripMenuItem20.Name = "toolStripMenuItem20";
|
||||
this.toolStripMenuItem20.Size = new System.Drawing.Size(258, 22);
|
||||
this.toolStripMenuItem20.Size = new System.Drawing.Size(257, 22);
|
||||
this.toolStripMenuItem20.Text = "Copy";
|
||||
this.toolStripMenuItem20.ToolTipText = "Copy the selected node.";
|
||||
this.toolStripMenuItem20.Click += new System.EventHandler(this.CopyNode);
|
||||
@ -1070,7 +1076,7 @@
|
||||
//
|
||||
this.toolStripMenuItem21.Image = global::CsbBuilder.Properties.Resources.Paste;
|
||||
this.toolStripMenuItem21.Name = "toolStripMenuItem21";
|
||||
this.toolStripMenuItem21.Size = new System.Drawing.Size(258, 22);
|
||||
this.toolStripMenuItem21.Size = new System.Drawing.Size(257, 22);
|
||||
this.toolStripMenuItem21.Text = "Paste";
|
||||
this.toolStripMenuItem21.ToolTipText = "Paste the copied node as child.";
|
||||
this.toolStripMenuItem21.Click += new System.EventHandler(this.PasteNode);
|
||||
@ -1079,7 +1085,7 @@
|
||||
//
|
||||
this.toolStripMenuItem1.Image = global::CsbBuilder.Properties.Resources.Remove;
|
||||
this.toolStripMenuItem1.Name = "toolStripMenuItem1";
|
||||
this.toolStripMenuItem1.Size = new System.Drawing.Size(258, 22);
|
||||
this.toolStripMenuItem1.Size = new System.Drawing.Size(257, 22);
|
||||
this.toolStripMenuItem1.Text = "Remove";
|
||||
this.toolStripMenuItem1.ToolTipText = "Remove the selected node.";
|
||||
this.toolStripMenuItem1.Click += new System.EventHandler(this.RemoveNode);
|
||||
@ -1087,13 +1093,13 @@
|
||||
// toolStripSeparator3
|
||||
//
|
||||
this.toolStripSeparator3.Name = "toolStripSeparator3";
|
||||
this.toolStripSeparator3.Size = new System.Drawing.Size(255, 6);
|
||||
this.toolStripSeparator3.Size = new System.Drawing.Size(254, 6);
|
||||
//
|
||||
// selectAisacReferenceToolStripMenuItem
|
||||
//
|
||||
this.selectAisacReferenceToolStripMenuItem.Image = global::CsbBuilder.Properties.Resources.Select;
|
||||
this.selectAisacReferenceToolStripMenuItem.Name = "selectAisacReferenceToolStripMenuItem";
|
||||
this.selectAisacReferenceToolStripMenuItem.Size = new System.Drawing.Size(258, 22);
|
||||
this.selectAisacReferenceToolStripMenuItem.Size = new System.Drawing.Size(257, 22);
|
||||
this.selectAisacReferenceToolStripMenuItem.Text = "Select AISAC Reference";
|
||||
this.selectAisacReferenceToolStripMenuItem.ToolTipText = "Select the referenced AISAC node from the AISAC tree.";
|
||||
this.selectAisacReferenceToolStripMenuItem.Click += new System.EventHandler(this.SelectAisacReference);
|
||||
@ -1102,7 +1108,7 @@
|
||||
//
|
||||
this.selectVoiceLimitGroupReferenceToolStripMenuItem.Image = global::CsbBuilder.Properties.Resources.Select;
|
||||
this.selectVoiceLimitGroupReferenceToolStripMenuItem.Name = "selectVoiceLimitGroupReferenceToolStripMenuItem";
|
||||
this.selectVoiceLimitGroupReferenceToolStripMenuItem.Size = new System.Drawing.Size(258, 22);
|
||||
this.selectVoiceLimitGroupReferenceToolStripMenuItem.Size = new System.Drawing.Size(257, 22);
|
||||
this.selectVoiceLimitGroupReferenceToolStripMenuItem.Text = "Select Voice Limit Group Reference";
|
||||
this.selectVoiceLimitGroupReferenceToolStripMenuItem.ToolTipText = "Select the referenced Voice Limit Group node from the Voice Limit Group tree.";
|
||||
this.selectVoiceLimitGroupReferenceToolStripMenuItem.Click += new System.EventHandler(this.SelectVoiceLimitGroupReference);
|
||||
@ -1110,13 +1116,13 @@
|
||||
// toolStripSeparator4
|
||||
//
|
||||
this.toolStripSeparator4.Name = "toolStripSeparator4";
|
||||
this.toolStripSeparator4.Size = new System.Drawing.Size(255, 6);
|
||||
this.toolStripSeparator4.Size = new System.Drawing.Size(254, 6);
|
||||
//
|
||||
// setAisacReferenceToolStripMenuItem
|
||||
//
|
||||
this.setAisacReferenceToolStripMenuItem.Image = global::CsbBuilder.Properties.Resources.SetReference;
|
||||
this.setAisacReferenceToolStripMenuItem.Name = "setAisacReferenceToolStripMenuItem";
|
||||
this.setAisacReferenceToolStripMenuItem.Size = new System.Drawing.Size(258, 22);
|
||||
this.setAisacReferenceToolStripMenuItem.Size = new System.Drawing.Size(257, 22);
|
||||
this.setAisacReferenceToolStripMenuItem.Text = "Set AISAC Reference";
|
||||
this.setAisacReferenceToolStripMenuItem.ToolTipText = "Set the AISAC reference from the AISAC tree.";
|
||||
this.setAisacReferenceToolStripMenuItem.Click += new System.EventHandler(this.SetAisacReference);
|
||||
@ -1125,7 +1131,7 @@
|
||||
//
|
||||
this.setVoiceLimitGroupReferenceToolStripMenuItem.Image = global::CsbBuilder.Properties.Resources.SetReference;
|
||||
this.setVoiceLimitGroupReferenceToolStripMenuItem.Name = "setVoiceLimitGroupReferenceToolStripMenuItem";
|
||||
this.setVoiceLimitGroupReferenceToolStripMenuItem.Size = new System.Drawing.Size(258, 22);
|
||||
this.setVoiceLimitGroupReferenceToolStripMenuItem.Size = new System.Drawing.Size(257, 22);
|
||||
this.setVoiceLimitGroupReferenceToolStripMenuItem.Text = "Set Voice Limit Group Reference";
|
||||
this.setVoiceLimitGroupReferenceToolStripMenuItem.ToolTipText = "Set the Voice Limit Group reference from the Voice Limit Group tree.";
|
||||
this.setVoiceLimitGroupReferenceToolStripMenuItem.Click += new System.EventHandler(this.SetVoiceLimitGroupReference);
|
||||
@ -1233,13 +1239,13 @@
|
||||
this.toolStripMenuItem8});
|
||||
this.trackItemMenu.Name = "cueAndVoiceLimitGroupMenu";
|
||||
this.trackItemMenu.RenderMode = System.Windows.Forms.ToolStripRenderMode.System;
|
||||
this.trackItemMenu.Size = new System.Drawing.Size(259, 242);
|
||||
this.trackItemMenu.Size = new System.Drawing.Size(258, 242);
|
||||
//
|
||||
// toolStripMenuItem33
|
||||
//
|
||||
this.toolStripMenuItem33.Image = global::CsbBuilder.Properties.Resources.Create;
|
||||
this.toolStripMenuItem33.Name = "toolStripMenuItem33";
|
||||
this.toolStripMenuItem33.Size = new System.Drawing.Size(258, 22);
|
||||
this.toolStripMenuItem33.Size = new System.Drawing.Size(257, 22);
|
||||
this.toolStripMenuItem33.Text = "Create";
|
||||
this.toolStripMenuItem33.ToolTipText = "Create a new node.";
|
||||
this.toolStripMenuItem33.Click += new System.EventHandler(this.CreateAndInsertSoundNode);
|
||||
@ -1247,13 +1253,13 @@
|
||||
// toolStripSeparator18
|
||||
//
|
||||
this.toolStripSeparator18.Name = "toolStripSeparator18";
|
||||
this.toolStripSeparator18.Size = new System.Drawing.Size(255, 6);
|
||||
this.toolStripSeparator18.Size = new System.Drawing.Size(254, 6);
|
||||
//
|
||||
// toolStripMenuItem23
|
||||
//
|
||||
this.toolStripMenuItem23.Image = global::CsbBuilder.Properties.Resources.Copy;
|
||||
this.toolStripMenuItem23.Name = "toolStripMenuItem23";
|
||||
this.toolStripMenuItem23.Size = new System.Drawing.Size(258, 22);
|
||||
this.toolStripMenuItem23.Size = new System.Drawing.Size(257, 22);
|
||||
this.toolStripMenuItem23.Text = "Copy";
|
||||
this.toolStripMenuItem23.ToolTipText = "Copy the selected node.";
|
||||
this.toolStripMenuItem23.Click += new System.EventHandler(this.CopyNode);
|
||||
@ -1262,7 +1268,7 @@
|
||||
//
|
||||
this.toolStripMenuItem30.Image = global::CsbBuilder.Properties.Resources.Paste;
|
||||
this.toolStripMenuItem30.Name = "toolStripMenuItem30";
|
||||
this.toolStripMenuItem30.Size = new System.Drawing.Size(258, 22);
|
||||
this.toolStripMenuItem30.Size = new System.Drawing.Size(257, 22);
|
||||
this.toolStripMenuItem30.Text = "Paste";
|
||||
this.toolStripMenuItem30.ToolTipText = "Paste the copied node after the selected node.";
|
||||
this.toolStripMenuItem30.Click += new System.EventHandler(this.PasteAndInsertNode);
|
||||
@ -1271,7 +1277,7 @@
|
||||
//
|
||||
this.toolStripMenuItem4.Image = global::CsbBuilder.Properties.Resources.Remove;
|
||||
this.toolStripMenuItem4.Name = "toolStripMenuItem4";
|
||||
this.toolStripMenuItem4.Size = new System.Drawing.Size(258, 22);
|
||||
this.toolStripMenuItem4.Size = new System.Drawing.Size(257, 22);
|
||||
this.toolStripMenuItem4.Text = "Remove";
|
||||
this.toolStripMenuItem4.ToolTipText = "Remove the selected node.";
|
||||
this.toolStripMenuItem4.Click += new System.EventHandler(this.RemoveNode);
|
||||
@ -1279,13 +1285,13 @@
|
||||
// toolStripSeparator6
|
||||
//
|
||||
this.toolStripSeparator6.Name = "toolStripSeparator6";
|
||||
this.toolStripSeparator6.Size = new System.Drawing.Size(255, 6);
|
||||
this.toolStripSeparator6.Size = new System.Drawing.Size(254, 6);
|
||||
//
|
||||
// selectSoundElementReferenceToolStripMenuItem
|
||||
//
|
||||
this.selectSoundElementReferenceToolStripMenuItem.Image = global::CsbBuilder.Properties.Resources.Select;
|
||||
this.selectSoundElementReferenceToolStripMenuItem.Name = "selectSoundElementReferenceToolStripMenuItem";
|
||||
this.selectSoundElementReferenceToolStripMenuItem.Size = new System.Drawing.Size(258, 22);
|
||||
this.selectSoundElementReferenceToolStripMenuItem.Size = new System.Drawing.Size(257, 22);
|
||||
this.selectSoundElementReferenceToolStripMenuItem.Text = "Select Sound Element Reference";
|
||||
this.selectSoundElementReferenceToolStripMenuItem.ToolTipText = "Select the referenced Sound Element node from the Sound Element tree.";
|
||||
this.selectSoundElementReferenceToolStripMenuItem.Click += new System.EventHandler(this.SelectSoundElementReference);
|
||||
@ -1294,7 +1300,7 @@
|
||||
//
|
||||
this.toolStripMenuItem5.Image = global::CsbBuilder.Properties.Resources.Select;
|
||||
this.toolStripMenuItem5.Name = "toolStripMenuItem5";
|
||||
this.toolStripMenuItem5.Size = new System.Drawing.Size(258, 22);
|
||||
this.toolStripMenuItem5.Size = new System.Drawing.Size(257, 22);
|
||||
this.toolStripMenuItem5.Text = "Select AISAC Reference";
|
||||
this.toolStripMenuItem5.ToolTipText = "Select the referenced AISAC node from the AISAC tree.";
|
||||
this.toolStripMenuItem5.Click += new System.EventHandler(this.SelectAisacReference);
|
||||
@ -1303,7 +1309,7 @@
|
||||
//
|
||||
this.toolStripMenuItem6.Image = global::CsbBuilder.Properties.Resources.Select;
|
||||
this.toolStripMenuItem6.Name = "toolStripMenuItem6";
|
||||
this.toolStripMenuItem6.Size = new System.Drawing.Size(258, 22);
|
||||
this.toolStripMenuItem6.Size = new System.Drawing.Size(257, 22);
|
||||
this.toolStripMenuItem6.Text = "Select Voice Limit Group Reference";
|
||||
this.toolStripMenuItem6.ToolTipText = "Select the referenced Voice Limit Group node from the Voice Limit Group tree.";
|
||||
this.toolStripMenuItem6.Click += new System.EventHandler(this.SelectVoiceLimitGroupReference);
|
||||
@ -1311,13 +1317,13 @@
|
||||
// toolStripSeparator7
|
||||
//
|
||||
this.toolStripSeparator7.Name = "toolStripSeparator7";
|
||||
this.toolStripSeparator7.Size = new System.Drawing.Size(255, 6);
|
||||
this.toolStripSeparator7.Size = new System.Drawing.Size(254, 6);
|
||||
//
|
||||
// setSoundElementReferenceToolStripMenuItem
|
||||
//
|
||||
this.setSoundElementReferenceToolStripMenuItem.Image = global::CsbBuilder.Properties.Resources.SetReference;
|
||||
this.setSoundElementReferenceToolStripMenuItem.Name = "setSoundElementReferenceToolStripMenuItem";
|
||||
this.setSoundElementReferenceToolStripMenuItem.Size = new System.Drawing.Size(258, 22);
|
||||
this.setSoundElementReferenceToolStripMenuItem.Size = new System.Drawing.Size(257, 22);
|
||||
this.setSoundElementReferenceToolStripMenuItem.Text = "Set Sound Element Reference";
|
||||
this.setSoundElementReferenceToolStripMenuItem.ToolTipText = "Set the Sound Element reference from the Sound Element tree.";
|
||||
this.setSoundElementReferenceToolStripMenuItem.Click += new System.EventHandler(this.SetSoundElementReference);
|
||||
@ -1326,7 +1332,7 @@
|
||||
//
|
||||
this.toolStripMenuItem7.Image = global::CsbBuilder.Properties.Resources.SetReference;
|
||||
this.toolStripMenuItem7.Name = "toolStripMenuItem7";
|
||||
this.toolStripMenuItem7.Size = new System.Drawing.Size(258, 22);
|
||||
this.toolStripMenuItem7.Size = new System.Drawing.Size(257, 22);
|
||||
this.toolStripMenuItem7.Text = "Set AISAC Reference";
|
||||
this.toolStripMenuItem7.ToolTipText = "Set the AISAC reference from the AISAC tree.";
|
||||
this.toolStripMenuItem7.Click += new System.EventHandler(this.SetAisacReference);
|
||||
@ -1335,7 +1341,7 @@
|
||||
//
|
||||
this.toolStripMenuItem8.Image = global::CsbBuilder.Properties.Resources.SetReference;
|
||||
this.toolStripMenuItem8.Name = "toolStripMenuItem8";
|
||||
this.toolStripMenuItem8.Size = new System.Drawing.Size(258, 22);
|
||||
this.toolStripMenuItem8.Size = new System.Drawing.Size(257, 22);
|
||||
this.toolStripMenuItem8.Text = "Set Voice Limit Group Reference";
|
||||
this.toolStripMenuItem8.ToolTipText = "Set the Voice Limit Group reference from the Voice Limit Group tree.";
|
||||
this.toolStripMenuItem8.Click += new System.EventHandler(this.SetVoiceLimitGroupReference);
|
||||
@ -1533,13 +1539,13 @@
|
||||
this.toolStripMenuItem38});
|
||||
this.aisacNodeMenu.Name = "cueAndVoiceLimitGroupMenu";
|
||||
this.aisacNodeMenu.RenderMode = System.Windows.Forms.ToolStripRenderMode.System;
|
||||
this.aisacNodeMenu.Size = new System.Drawing.Size(154, 148);
|
||||
this.aisacNodeMenu.Size = new System.Drawing.Size(153, 148);
|
||||
//
|
||||
// toolStripMenuItem35
|
||||
//
|
||||
this.toolStripMenuItem35.Image = global::CsbBuilder.Properties.Resources.Create;
|
||||
this.toolStripMenuItem35.Name = "toolStripMenuItem35";
|
||||
this.toolStripMenuItem35.Size = new System.Drawing.Size(153, 22);
|
||||
this.toolStripMenuItem35.Size = new System.Drawing.Size(152, 22);
|
||||
this.toolStripMenuItem35.Text = "Create";
|
||||
this.toolStripMenuItem35.ToolTipText = "Create a new node after the selected node.";
|
||||
this.toolStripMenuItem35.Click += new System.EventHandler(this.CreateAndInsertNode);
|
||||
@ -1547,13 +1553,13 @@
|
||||
// toolStripSeparator20
|
||||
//
|
||||
this.toolStripSeparator20.Name = "toolStripSeparator20";
|
||||
this.toolStripSeparator20.Size = new System.Drawing.Size(150, 6);
|
||||
this.toolStripSeparator20.Size = new System.Drawing.Size(149, 6);
|
||||
//
|
||||
// loadTemplateToolStripMenuItem
|
||||
//
|
||||
this.loadTemplateToolStripMenuItem.Image = global::CsbBuilder.Properties.Resources.Template;
|
||||
this.loadTemplateToolStripMenuItem.Name = "loadTemplateToolStripMenuItem";
|
||||
this.loadTemplateToolStripMenuItem.Size = new System.Drawing.Size(153, 22);
|
||||
this.loadTemplateToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
|
||||
this.loadTemplateToolStripMenuItem.Text = "Load Template";
|
||||
this.loadTemplateToolStripMenuItem.Click += new System.EventHandler(this.LoadTemplate);
|
||||
//
|
||||
@ -1561,20 +1567,20 @@
|
||||
//
|
||||
this.saveTemplateToolStripMenuItem.Image = global::CsbBuilder.Properties.Resources.Template;
|
||||
this.saveTemplateToolStripMenuItem.Name = "saveTemplateToolStripMenuItem";
|
||||
this.saveTemplateToolStripMenuItem.Size = new System.Drawing.Size(153, 22);
|
||||
this.saveTemplateToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
|
||||
this.saveTemplateToolStripMenuItem.Text = "Save Template";
|
||||
this.saveTemplateToolStripMenuItem.Click += new System.EventHandler(this.SaveTemplate);
|
||||
//
|
||||
// toolStripSeparator21
|
||||
//
|
||||
this.toolStripSeparator21.Name = "toolStripSeparator21";
|
||||
this.toolStripSeparator21.Size = new System.Drawing.Size(150, 6);
|
||||
this.toolStripSeparator21.Size = new System.Drawing.Size(149, 6);
|
||||
//
|
||||
// toolStripMenuItem36
|
||||
//
|
||||
this.toolStripMenuItem36.Image = global::CsbBuilder.Properties.Resources.Copy;
|
||||
this.toolStripMenuItem36.Name = "toolStripMenuItem36";
|
||||
this.toolStripMenuItem36.Size = new System.Drawing.Size(153, 22);
|
||||
this.toolStripMenuItem36.Size = new System.Drawing.Size(152, 22);
|
||||
this.toolStripMenuItem36.Text = "Copy";
|
||||
this.toolStripMenuItem36.ToolTipText = "Copy the selected node.";
|
||||
this.toolStripMenuItem36.Click += new System.EventHandler(this.CopyNode);
|
||||
@ -1583,7 +1589,7 @@
|
||||
//
|
||||
this.toolStripMenuItem37.Image = global::CsbBuilder.Properties.Resources.Paste;
|
||||
this.toolStripMenuItem37.Name = "toolStripMenuItem37";
|
||||
this.toolStripMenuItem37.Size = new System.Drawing.Size(153, 22);
|
||||
this.toolStripMenuItem37.Size = new System.Drawing.Size(152, 22);
|
||||
this.toolStripMenuItem37.Text = "Paste";
|
||||
this.toolStripMenuItem37.ToolTipText = "Paste the copied node after the selected node.";
|
||||
this.toolStripMenuItem37.Click += new System.EventHandler(this.PasteAndInsertNode);
|
||||
@ -1592,7 +1598,7 @@
|
||||
//
|
||||
this.toolStripMenuItem38.Image = global::CsbBuilder.Properties.Resources.Remove;
|
||||
this.toolStripMenuItem38.Name = "toolStripMenuItem38";
|
||||
this.toolStripMenuItem38.Size = new System.Drawing.Size(153, 22);
|
||||
this.toolStripMenuItem38.Size = new System.Drawing.Size(152, 22);
|
||||
this.toolStripMenuItem38.Text = "Remove";
|
||||
this.toolStripMenuItem38.ToolTipText = "Remove the selected node.";
|
||||
this.toolStripMenuItem38.Click += new System.EventHandler(this.RemoveNode);
|
||||
@ -1610,13 +1616,13 @@
|
||||
this.toolStripMenuItem43});
|
||||
this.aisacFolderMenu.Name = "synthSoundElementAndAisacMenu";
|
||||
this.aisacFolderMenu.RenderMode = System.Windows.Forms.ToolStripRenderMode.System;
|
||||
this.aisacFolderMenu.Size = new System.Drawing.Size(190, 148);
|
||||
this.aisacFolderMenu.Size = new System.Drawing.Size(189, 148);
|
||||
//
|
||||
// toolStripMenuItem39
|
||||
//
|
||||
this.toolStripMenuItem39.Image = global::CsbBuilder.Properties.Resources.Create;
|
||||
this.toolStripMenuItem39.Name = "toolStripMenuItem39";
|
||||
this.toolStripMenuItem39.Size = new System.Drawing.Size(189, 22);
|
||||
this.toolStripMenuItem39.Size = new System.Drawing.Size(188, 22);
|
||||
this.toolStripMenuItem39.Text = "Create";
|
||||
this.toolStripMenuItem39.ToolTipText = "Create a new child node.";
|
||||
this.toolStripMenuItem39.Click += new System.EventHandler(this.CreateChildNode);
|
||||
@ -1625,7 +1631,7 @@
|
||||
//
|
||||
this.toolStripMenuItem40.Image = global::CsbBuilder.Properties.Resources.Folder;
|
||||
this.toolStripMenuItem40.Name = "toolStripMenuItem40";
|
||||
this.toolStripMenuItem40.Size = new System.Drawing.Size(189, 22);
|
||||
this.toolStripMenuItem40.Size = new System.Drawing.Size(188, 22);
|
||||
this.toolStripMenuItem40.Text = "Create Folder";
|
||||
this.toolStripMenuItem40.ToolTipText = "Create a new child folder.";
|
||||
this.toolStripMenuItem40.Click += new System.EventHandler(this.CreateChildFolder);
|
||||
@ -1633,26 +1639,26 @@
|
||||
// toolStripSeparator22
|
||||
//
|
||||
this.toolStripSeparator22.Name = "toolStripSeparator22";
|
||||
this.toolStripSeparator22.Size = new System.Drawing.Size(186, 6);
|
||||
this.toolStripSeparator22.Size = new System.Drawing.Size(185, 6);
|
||||
//
|
||||
// toolStripMenuItem44
|
||||
//
|
||||
this.toolStripMenuItem44.Image = global::CsbBuilder.Properties.Resources.Template;
|
||||
this.toolStripMenuItem44.Name = "toolStripMenuItem44";
|
||||
this.toolStripMenuItem44.Size = new System.Drawing.Size(189, 22);
|
||||
this.toolStripMenuItem44.Size = new System.Drawing.Size(188, 22);
|
||||
this.toolStripMenuItem44.Text = "Load AISAC Template";
|
||||
this.toolStripMenuItem44.Click += new System.EventHandler(this.LoadTemplate);
|
||||
//
|
||||
// toolStripSeparator23
|
||||
//
|
||||
this.toolStripSeparator23.Name = "toolStripSeparator23";
|
||||
this.toolStripSeparator23.Size = new System.Drawing.Size(186, 6);
|
||||
this.toolStripSeparator23.Size = new System.Drawing.Size(185, 6);
|
||||
//
|
||||
// toolStripMenuItem41
|
||||
//
|
||||
this.toolStripMenuItem41.Image = global::CsbBuilder.Properties.Resources.Copy;
|
||||
this.toolStripMenuItem41.Name = "toolStripMenuItem41";
|
||||
this.toolStripMenuItem41.Size = new System.Drawing.Size(189, 22);
|
||||
this.toolStripMenuItem41.Size = new System.Drawing.Size(188, 22);
|
||||
this.toolStripMenuItem41.Text = "Copy";
|
||||
this.toolStripMenuItem41.ToolTipText = "Copy the selected node.";
|
||||
this.toolStripMenuItem41.Click += new System.EventHandler(this.CopyNode);
|
||||
@ -1661,7 +1667,7 @@
|
||||
//
|
||||
this.toolStripMenuItem42.Image = global::CsbBuilder.Properties.Resources.Paste;
|
||||
this.toolStripMenuItem42.Name = "toolStripMenuItem42";
|
||||
this.toolStripMenuItem42.Size = new System.Drawing.Size(189, 22);
|
||||
this.toolStripMenuItem42.Size = new System.Drawing.Size(188, 22);
|
||||
this.toolStripMenuItem42.Text = "Paste";
|
||||
this.toolStripMenuItem42.ToolTipText = "Paste the copied node as child.";
|
||||
this.toolStripMenuItem42.Click += new System.EventHandler(this.PasteNode);
|
||||
@ -1670,11 +1676,16 @@
|
||||
//
|
||||
this.toolStripMenuItem43.Image = global::CsbBuilder.Properties.Resources.Remove;
|
||||
this.toolStripMenuItem43.Name = "toolStripMenuItem43";
|
||||
this.toolStripMenuItem43.Size = new System.Drawing.Size(189, 22);
|
||||
this.toolStripMenuItem43.Size = new System.Drawing.Size(188, 22);
|
||||
this.toolStripMenuItem43.Text = "Remove";
|
||||
this.toolStripMenuItem43.ToolTipText = "Remove the selected node.";
|
||||
this.toolStripMenuItem43.Click += new System.EventHandler(this.RemoveNode);
|
||||
//
|
||||
// toolStripSeparator27
|
||||
//
|
||||
this.toolStripSeparator27.Name = "toolStripSeparator27";
|
||||
this.toolStripSeparator27.Size = new System.Drawing.Size(203, 6);
|
||||
//
|
||||
// MainForm
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
@ -1879,11 +1890,12 @@
|
||||
private System.Windows.Forms.ToolStripSeparator toolStripSeparator26;
|
||||
private System.Windows.Forms.ToolStripMenuItem settingsButton;
|
||||
private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem49;
|
||||
private System.Windows.Forms.ToolStripMenuItem aDXToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem aAXToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem extractAAXToFolderToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem packFolderToAAXToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem convertADXsToWAVToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem convertAndSplitLoopingToWAVToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripSeparator toolStripSeparator27;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,9 +13,10 @@ using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Xml;
|
||||
using System.Xml.Serialization;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using CsbBuilder.Builder;
|
||||
using CsbBuilder.BuilderNode;
|
||||
using CsbBuilder.BuilderNodes;
|
||||
using CsbBuilder.Audio;
|
||||
using CsbBuilder.Importer;
|
||||
using CsbBuilder.Project;
|
||||
@ -23,7 +24,7 @@ using CsbBuilder.Serialization;
|
||||
using CsbBuilder.Properties;
|
||||
|
||||
using SonicAudioLib.IO;
|
||||
using SonicAudioLib.Archive;
|
||||
using SonicAudioLib.Archives;
|
||||
|
||||
using NAudio.Wave;
|
||||
|
||||
@ -42,6 +43,25 @@ namespace CsbBuilder
|
||||
|
||||
private List<IWavePlayer> sounds = new List<IWavePlayer>();
|
||||
|
||||
private string filters = null;
|
||||
|
||||
private string Filters
|
||||
{
|
||||
get
|
||||
{
|
||||
if (string.IsNullOrEmpty(filters))
|
||||
{
|
||||
var culture = Thread.CurrentThread.CurrentUICulture;
|
||||
|
||||
var formats = VGMStreamNative.GetFormats().OrderBy(format => format);
|
||||
var formatFilter = formats.Select(format => $"{format.ToUpper(culture)} Files|*.{format}");
|
||||
filters = $"All Formats|{string.Join(";", formats.Select(format => $"*.{format}"))}|{string.Join("|", formatFilter)}";
|
||||
}
|
||||
|
||||
return filters;
|
||||
}
|
||||
}
|
||||
|
||||
public MainForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
@ -1388,10 +1408,12 @@ namespace CsbBuilder
|
||||
|
||||
public void ReadAdx(string path, out uint sampleRate, out byte channelCount, out uint sampleCount)
|
||||
{
|
||||
AdxHeader header = AdxFileReader.LoadHeader(path);
|
||||
sampleRate = header.SampleRate;
|
||||
channelCount = header.ChannelCount;
|
||||
sampleCount = header.SampleCount;
|
||||
using (var reader = new VGMStreamReader(path))
|
||||
{
|
||||
sampleRate = (uint)reader.WaveFormat.SampleRate;
|
||||
channelCount = (byte)reader.WaveFormat.Channels;
|
||||
sampleCount = (uint)(reader.Length / 2);
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateChildSoundNode(object sender, EventArgs e)
|
||||
@ -1424,36 +1446,100 @@ namespace CsbBuilder
|
||||
return (int)(miliseconds * sampleRate / 1000.0) * channelCount * bitsPerSample / 8;
|
||||
}
|
||||
|
||||
private void AddSoundElementSound(BuilderSoundElementNode soundElementNode, double volume, double pitch, int sampleCount, int delayTime)
|
||||
private int GetMilisecondsFromByteCount(int byteCount, int sampleRate, int channelCount, int bitsPerSample)
|
||||
{
|
||||
return (int)((8000.0 * byteCount) / (sampleRate * channelCount * bitsPerSample));
|
||||
}
|
||||
|
||||
private WaveStream GetWaveStream(string path)
|
||||
{
|
||||
if (path.EndsWith(".wav", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return new WaveFileReader(project.GetFullAudioPath(path));
|
||||
}
|
||||
|
||||
return new VGMStreamReader(project.GetFullAudioPath(path));
|
||||
}
|
||||
|
||||
private void AddSoundElementSound(BuilderSoundElementNode soundElementNode, double volume, double pitch, int delayTime)
|
||||
{
|
||||
WaveStream waveStream = null;
|
||||
|
||||
if (!string.IsNullOrEmpty(soundElementNode.Intro) && string.IsNullOrEmpty(soundElementNode.Loop))
|
||||
{
|
||||
waveStream = new AdxFileReader(project.GetFullAudioPath(soundElementNode.Intro)) { Volume = volume, Pitch = pitch, DelayTime = delayTime };
|
||||
var reader = new VGMStreamReader(project.GetFullAudioPath(soundElementNode.Intro));
|
||||
reader.DisableLoop();
|
||||
|
||||
waveStream = new ExtendedWaveStream(reader)
|
||||
{
|
||||
DelayTime = delayTime,
|
||||
Volume = volume,
|
||||
Pitch = pitch,
|
||||
};
|
||||
}
|
||||
|
||||
else if (string.IsNullOrEmpty(soundElementNode.Intro) && !string.IsNullOrEmpty(soundElementNode.Loop))
|
||||
{
|
||||
waveStream = new ExtendedAdxFileReader(project.GetFullAudioPath(soundElementNode.Loop)) { Volume = volume, Pitch = pitch, DelayTime = delayTime };
|
||||
var reader = new VGMStreamReader(project.GetFullAudioPath(soundElementNode.Loop));
|
||||
reader.ForceLoop();
|
||||
|
||||
waveStream = new ExtendedWaveStream(reader)
|
||||
{
|
||||
DelayTime = delayTime,
|
||||
Volume = volume,
|
||||
Pitch = pitch,
|
||||
ForceLoop = true,
|
||||
};
|
||||
}
|
||||
|
||||
else if (!string.IsNullOrEmpty(soundElementNode.Intro) && !string.IsNullOrEmpty(soundElementNode.Loop))
|
||||
{
|
||||
waveStream = new ExtendedAdxFileReader(project.GetFullAudioPath(soundElementNode.Intro), project.GetFullAudioPath(soundElementNode.Loop)) { Volume = volume, Pitch = pitch, DelayTime = delayTime };
|
||||
var intro = new VGMStreamReader(project.GetFullAudioPath(soundElementNode.Intro));
|
||||
intro.DisableLoop();
|
||||
|
||||
var loop = new VGMStreamReader(project.GetFullAudioPath(soundElementNode.Loop));
|
||||
loop.ForceLoop();
|
||||
|
||||
waveStream = new ExtendedWaveStream(intro, loop)
|
||||
{
|
||||
DelayTime = delayTime,
|
||||
Volume = volume,
|
||||
Pitch = pitch,
|
||||
ForceLoop = true,
|
||||
};
|
||||
}
|
||||
|
||||
if (waveStream != null)
|
||||
{
|
||||
DirectSoundOut waveOut = new DirectSoundOut();
|
||||
waveOut.Init(waveStream);
|
||||
sounds.Add(waveOut);
|
||||
IWavePlayer wavePlayer = null;
|
||||
|
||||
switch (Settings.WavePlayer)
|
||||
{
|
||||
case Settings.NAudioWavePlayer.WaveOut:
|
||||
wavePlayer = new WaveOut();
|
||||
break;
|
||||
|
||||
case Settings.NAudioWavePlayer.WasapiOut:
|
||||
wavePlayer = new WasapiOut();
|
||||
break;
|
||||
|
||||
case Settings.NAudioWavePlayer.DirectSoundOut:
|
||||
wavePlayer = new DirectSoundOut();
|
||||
break;
|
||||
|
||||
case Settings.NAudioWavePlayer.AsioOut:
|
||||
wavePlayer = new AsioOut();
|
||||
break;
|
||||
}
|
||||
|
||||
wavePlayer.Init(waveStream);
|
||||
sounds.Add(wavePlayer);
|
||||
}
|
||||
}
|
||||
|
||||
private void AddSoundElementSound(TreeNode soundElementTreeNode, double volume, double pitch, int sampleCount, int delayTime)
|
||||
private void AddSoundElementSound(TreeNode soundElementTreeNode, double volume, double pitch, int delayTime)
|
||||
{
|
||||
AddSoundElementSound((BuilderSoundElementNode)soundElementTreeNode.Tag, volume, pitch, sampleCount, delayTime);
|
||||
AddSoundElementSound((BuilderSoundElementNode)soundElementTreeNode.Tag, volume, pitch, delayTime);
|
||||
}
|
||||
|
||||
private double GetSecondsFromSampleCount(int sampleCount, int sampleRate)
|
||||
@ -1504,7 +1590,7 @@ namespace CsbBuilder
|
||||
synthTreeNode = synthTreeNode.Parent;
|
||||
}
|
||||
|
||||
return pitch / 100.0;
|
||||
return pitch / 1500.0;
|
||||
}
|
||||
|
||||
private double GetAbsoluteVolume(TreeNode synthTreeNode)
|
||||
@ -1515,7 +1601,7 @@ namespace CsbBuilder
|
||||
{
|
||||
if (synthTreeNode.Tag is BuilderSynthNode synthNode)
|
||||
{
|
||||
volume = (volume * synthNode.Volume) / 1000;
|
||||
volume = (volume * synthNode.Volume) / 1000.0;
|
||||
}
|
||||
|
||||
synthTreeNode = synthTreeNode.Parent;
|
||||
@ -1541,7 +1627,7 @@ namespace CsbBuilder
|
||||
return delayTime;
|
||||
}
|
||||
|
||||
private void AddSynthSound(TreeNode synthTreeNode, int sampleCount)
|
||||
private void AddSynthSound(TreeNode synthTreeNode)
|
||||
{
|
||||
BuilderSynthNode synthNode = (BuilderSynthNode)synthTreeNode.Tag;
|
||||
|
||||
@ -1554,12 +1640,12 @@ namespace CsbBuilder
|
||||
|
||||
if (childSynthNode.Type == BuilderSynthType.Single && !string.IsNullOrEmpty(childSynthNode.SoundElementReference) && childSynthNode.PlayThisTurn)
|
||||
{
|
||||
AddSoundElementSound(soundElementTree.FindNodeByFullPath(childSynthNode.SoundElementReference), GetAbsoluteVolume(childNode), GetAbsolutePitch(childNode), sampleCount, GetAbsoluteDelayTime(childNode));
|
||||
AddSoundElementSound(soundElementTree.FindNodeByFullPath(childSynthNode.SoundElementReference), GetAbsoluteVolume(childNode), GetAbsolutePitch(childNode), GetAbsoluteDelayTime(childNode));
|
||||
}
|
||||
|
||||
else if (childSynthNode.Type == BuilderSynthType.WithChildren)
|
||||
{
|
||||
AddSynthSound(childNode, sampleCount);
|
||||
AddSynthSound(childNode);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1570,12 +1656,12 @@ namespace CsbBuilder
|
||||
|
||||
if (childSynthNode.Type == BuilderSynthType.Single && !string.IsNullOrEmpty(childSynthNode.SoundElementReference) && childSynthNode.PlayThisTurn)
|
||||
{
|
||||
AddSoundElementSound(soundElementTree.FindNodeByFullPath(childSynthNode.SoundElementReference), GetAbsoluteVolume(childNode), GetAbsolutePitch(childNode), sampleCount, GetAbsoluteDelayTime(childNode));
|
||||
AddSoundElementSound(soundElementTree.FindNodeByFullPath(childSynthNode.SoundElementReference), GetAbsoluteVolume(childNode), GetAbsolutePitch(childNode), GetAbsoluteDelayTime(childNode));
|
||||
}
|
||||
|
||||
else if (childSynthNode.Type == BuilderSynthType.WithChildren)
|
||||
{
|
||||
AddSynthSound(childNode, sampleCount);
|
||||
AddSynthSound(childNode);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1587,12 +1673,12 @@ namespace CsbBuilder
|
||||
|
||||
if (childSynthNode.Type == BuilderSynthType.Single && !string.IsNullOrEmpty(childSynthNode.SoundElementReference) && childSynthNode.PlayThisTurn)
|
||||
{
|
||||
AddSoundElementSound(soundElementTree.FindNodeByFullPath(childSynthNode.SoundElementReference), GetAbsoluteVolume(childNode), GetAbsolutePitch(childNode), sampleCount, GetAbsoluteDelayTime(childNode));
|
||||
AddSoundElementSound(soundElementTree.FindNodeByFullPath(childSynthNode.SoundElementReference), GetAbsoluteVolume(childNode), GetAbsolutePitch(childNode), GetAbsoluteDelayTime(childNode));
|
||||
}
|
||||
|
||||
else if (childSynthNode.Type == BuilderSynthType.WithChildren)
|
||||
{
|
||||
AddSynthSound(childNode, sampleCount);
|
||||
AddSynthSound(childNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1602,7 +1688,7 @@ namespace CsbBuilder
|
||||
{
|
||||
if (!string.IsNullOrEmpty(synthNode.SoundElementReference) && synthNode.PlayThisTurn)
|
||||
{
|
||||
AddSoundElementSound(soundElementTree.FindNodeByFullPath(synthNode.SoundElementReference), synthNode.Volume / 1000.0, synthNode.Pitch / 1000.0, GetTheBiggestSampleCount(synthTreeNode), (int)synthNode.DelayTime);
|
||||
AddSoundElementSound(soundElementTree.FindNodeByFullPath(synthNode.SoundElementReference), synthNode.Volume / 1000.0, synthNode.Pitch / 1500.0, (int)synthNode.DelayTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1624,18 +1710,18 @@ namespace CsbBuilder
|
||||
if (!string.IsNullOrEmpty(cueNode.SynthReference))
|
||||
{
|
||||
TreeNode synthNode = synthTree.FindNodeByFullPath(cueNode.SynthReference);
|
||||
AddSynthSound(synthNode, GetTheBiggestSampleCount(synthNode));
|
||||
AddSynthSound(synthNode);
|
||||
}
|
||||
}
|
||||
|
||||
else if (soundElementTree.Focused && soundElementTree.SelectedNode != null && soundElementTree.SelectedNode.Tag is BuilderSoundElementNode)
|
||||
{
|
||||
AddSoundElementSound(soundElementTree.SelectedNode, 1, 0, -1, 0);
|
||||
AddSoundElementSound(soundElementTree.SelectedNode, 1, 0, 0);
|
||||
}
|
||||
|
||||
else if (synthTree.Focused && synthTree.SelectedNode != null && synthTree.SelectedNode.Tag is BuilderSynthNode)
|
||||
{
|
||||
AddSynthSound(synthTree.SelectedNode, GetTheBiggestSampleCount(synthTree.SelectedNode));
|
||||
AddSynthSound(synthTree.SelectedNode);
|
||||
}
|
||||
|
||||
sounds.ForEach(sound => sound.Play());
|
||||
@ -2140,10 +2226,9 @@ namespace CsbBuilder
|
||||
{
|
||||
using (OpenFileDialog openFileDialog = new OpenFileDialog
|
||||
{
|
||||
Title = "Convert ADX Files",
|
||||
FileName = "Select ADX files you want to convert and press Open",
|
||||
Filter = "ADX Files|*.adx",
|
||||
DefaultExt = "adx",
|
||||
Title = "Convert Audio Files",
|
||||
FileName = "Select audio files you want to convert and press Open",
|
||||
Filter = Filters,
|
||||
Multiselect = true,
|
||||
})
|
||||
{
|
||||
@ -2157,23 +2242,88 @@ namespace CsbBuilder
|
||||
{
|
||||
if (saveFileDialog.ShowDialog(this) == DialogResult.OK)
|
||||
{
|
||||
foreach (string fileName in openFileDialog.FileNames)
|
||||
var failedFiles = new List<string>();
|
||||
|
||||
Action<string> action = fileName =>
|
||||
{
|
||||
using (AdxFileReader reader = new AdxFileReader(fileName))
|
||||
VGMStreamReader reader = null;
|
||||
|
||||
try
|
||||
{
|
||||
reader = new VGMStreamReader(fileName);
|
||||
}
|
||||
|
||||
catch (NullReferenceException)
|
||||
{
|
||||
failedFiles.Add(Path.GetFileName(fileName));
|
||||
return;
|
||||
}
|
||||
|
||||
using (reader)
|
||||
using (WaveFileWriter writer = new WaveFileWriter(
|
||||
Path.Combine(
|
||||
Path.GetDirectoryName(saveFileDialog.FileName),
|
||||
Path.GetFileNameWithoutExtension(fileName) + ".wav"),
|
||||
reader.WaveFormat))
|
||||
{
|
||||
int num;
|
||||
byte[] buffer = new byte[Settings.BufferSize];
|
||||
|
||||
while ((num = reader.Read(buffer, 0, Settings.BufferSize)) != 0)
|
||||
if (reader.LoopFlag)
|
||||
{
|
||||
writer.Write(buffer, 0, num);
|
||||
// Intro
|
||||
DataStream.CopyPartTo(reader, writer, reader.LoopStartPosition, Settings.BufferSize);
|
||||
|
||||
// Loops
|
||||
DataStream.CopyPartTo(reader, writer, (reader.LoopEndPosition - reader.LoopStartPosition) * Settings.LoopCount, Settings.BufferSize);
|
||||
|
||||
// Last loop, fade away
|
||||
byte[] buffer = new byte[Settings.BufferSize];
|
||||
|
||||
// Fade will be 10 seconds
|
||||
double sampleCount = (int)(reader.WaveFormat.AverageBytesPerSecond * Settings.FadeTime);
|
||||
|
||||
int i;
|
||||
int j = (int)(sampleCount + reader.WaveFormat.AverageBytesPerSecond * Settings.FadeDelay);
|
||||
|
||||
while (j > 0)
|
||||
{
|
||||
reader.Read(buffer, 0, buffer.Length);
|
||||
|
||||
for (i = 0; i < buffer.Length && j > 0; i += 2, j--)
|
||||
{
|
||||
double volume = j / sampleCount;
|
||||
|
||||
// Clamp to 0.0-1.0 range so delay actually works
|
||||
volume = volume > 1.0 ? 1.0 : volume;
|
||||
|
||||
PostSampleEditor.ApplyVolume(buffer, i, volume);
|
||||
}
|
||||
|
||||
writer.Write(buffer, 0, i);
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
DataStream.CopyTo(reader, writer, Settings.BufferSize);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (Settings.EnableThreading)
|
||||
{
|
||||
Parallel.ForEach(openFileDialog.FileNames, new ParallelOptions { MaxDegreeOfParallelism = Settings.MaxThreads }, action);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
foreach (var item in openFileDialog.FileNames)
|
||||
{
|
||||
action(item);
|
||||
}
|
||||
}
|
||||
|
||||
if (failedFiles.Count != 0)
|
||||
{
|
||||
MessageBox.Show($"Following files could not be converted:\n{string.Join("\n", failedFiles)}", "CSB Builder", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2202,6 +2352,11 @@ namespace CsbBuilder
|
||||
{
|
||||
if (saveFileDialog.ShowDialog(this) == DialogResult.OK)
|
||||
{
|
||||
DataExtractor extractor = new DataExtractor();
|
||||
extractor.EnableThreading = Settings.EnableThreading;
|
||||
extractor.MaxThreads = Settings.MaxThreads;
|
||||
extractor.BufferSize = Settings.BufferSize;
|
||||
|
||||
foreach (string fileName in openFileDialog.FileNames)
|
||||
{
|
||||
CriAaxArchive aaxArchive = new CriAaxArchive();
|
||||
@ -2210,15 +2365,17 @@ namespace CsbBuilder
|
||||
foreach (CriAaxEntry entry in aaxArchive)
|
||||
{
|
||||
using (Stream source = File.OpenRead(fileName))
|
||||
using (Stream destination = File.Create(
|
||||
Path.Combine(
|
||||
Path.GetDirectoryName(saveFileDialog.FileName),
|
||||
$"{Path.GetFileNameWithoutExtension(fileName)}_{entry.Flag}.adx")))
|
||||
{
|
||||
EndianStream.CopyPartTo(source, destination, entry.Position, entry.Length, Settings.BufferSize);
|
||||
extractor.Add(fileName, Path.Combine(
|
||||
Path.GetDirectoryName(saveFileDialog.FileName),
|
||||
$"{Path.GetFileNameWithoutExtension(fileName)}_{entry.Flag}{aaxArchive.GetModeExtension()}"),
|
||||
entry.Position,
|
||||
entry.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extractor.Run();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2229,10 +2386,9 @@ namespace CsbBuilder
|
||||
{
|
||||
using (OpenFileDialog openFileDialog = new OpenFileDialog
|
||||
{
|
||||
Title = "Extract ADX Files",
|
||||
Title = "Pack ADX Files",
|
||||
FileName = "Select ADX files you want to pack and press Open",
|
||||
Filter = "ADX Files|*.adx",
|
||||
DefaultExt = "adx",
|
||||
Filter = "All Files|*.adx;*.wav|ADX Files|*.adx|WAV Files|*.wav",
|
||||
Multiselect = true,
|
||||
})
|
||||
{
|
||||
@ -2246,6 +2402,13 @@ namespace CsbBuilder
|
||||
MessageBox.Show("You can select maximum 2 ADX files.", "CSB Builder", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
|
||||
else if (openFileDialog.FileNames.Length == 2 &&
|
||||
!Path.GetExtension(openFileDialog.FileNames[0]).Equals(
|
||||
Path.GetExtension(openFileDialog.FileNames[1]), StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
MessageBox.Show("You can select only the same type of files.", "CSB Builder", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
files = openFileDialog.FileNames;
|
||||
@ -2258,7 +2421,7 @@ namespace CsbBuilder
|
||||
using (SaveFileDialog saveFileDialog = new SaveFileDialog
|
||||
{
|
||||
Title = "Output File",
|
||||
FileName = "*.aax",
|
||||
FileName = $"{Path.GetFileNameWithoutExtension(files[0])}.aax",
|
||||
Filter = "AAX Files|*.aax",
|
||||
DefaultExt = "aax",
|
||||
})
|
||||
@ -2266,6 +2429,7 @@ namespace CsbBuilder
|
||||
if (saveFileDialog.ShowDialog(this) == DialogResult.OK)
|
||||
{
|
||||
CriAaxArchive archive = new CriAaxArchive();
|
||||
archive.SetModeFromExtension(files[0]);
|
||||
|
||||
for (int i = 0; i < files.Length; i++)
|
||||
{
|
||||
@ -2278,5 +2442,96 @@ namespace CsbBuilder
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void convertAndSplitLoopingToWAVToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
using (OpenFileDialog openFileDialog = new OpenFileDialog
|
||||
{
|
||||
Title = "Convert And Split Audio Files",
|
||||
FileName = "Select audio files you want to convert and press Open",
|
||||
Filter = Filters,
|
||||
Multiselect = true,
|
||||
})
|
||||
{
|
||||
if (openFileDialog.ShowDialog(this) == DialogResult.OK)
|
||||
{
|
||||
using (SaveFileDialog saveFileDialog = new SaveFileDialog
|
||||
{
|
||||
Title = "Output Directory",
|
||||
FileName = "Enter into a directory and press Save",
|
||||
})
|
||||
{
|
||||
if (saveFileDialog.ShowDialog(this) == DialogResult.OK)
|
||||
{
|
||||
var failedFiles = new List<string>();
|
||||
|
||||
Action<string> action = fileName =>
|
||||
{
|
||||
VGMStreamReader reader = null;
|
||||
|
||||
try
|
||||
{
|
||||
reader = new VGMStreamReader(fileName);
|
||||
}
|
||||
|
||||
catch (NullReferenceException)
|
||||
{
|
||||
failedFiles.Add(Path.GetFileName(fileName));
|
||||
return;
|
||||
}
|
||||
|
||||
using (reader)
|
||||
{
|
||||
string outputFileName =
|
||||
Path.Combine(
|
||||
Path.GetDirectoryName(saveFileDialog.FileName),
|
||||
Path.GetFileNameWithoutExtension(fileName));
|
||||
|
||||
WaveFileWriter introWriter;
|
||||
WaveFileWriter loopWriter;
|
||||
|
||||
if (reader.LoopFlag)
|
||||
{
|
||||
using (introWriter = new WaveFileWriter(outputFileName + "_Intro.wav", reader.WaveFormat))
|
||||
using (loopWriter = new WaveFileWriter(outputFileName + "_Loop.wav", reader.WaveFormat))
|
||||
{
|
||||
DataStream.CopyPartTo(reader, introWriter, 0, reader.LoopStartPosition, Settings.BufferSize);
|
||||
DataStream.CopyPartTo(reader, loopWriter, reader.LoopStartPosition, reader.LoopEndPosition - reader.LoopStartPosition, Settings.BufferSize);
|
||||
}
|
||||
}
|
||||
|
||||
// No loop enabled, directly extract the intro
|
||||
else
|
||||
{
|
||||
using (introWriter = new WaveFileWriter(outputFileName + "_Intro.wav", reader.WaveFormat))
|
||||
{
|
||||
DataStream.CopyTo(reader, introWriter, Settings.BufferSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (Settings.EnableThreading)
|
||||
{
|
||||
Parallel.ForEach(openFileDialog.FileNames, new ParallelOptions { MaxDegreeOfParallelism = Settings.MaxThreads }, action);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
foreach (var item in openFileDialog.FileNames)
|
||||
{
|
||||
action(item);
|
||||
}
|
||||
}
|
||||
|
||||
if (failedFiles.Count != 0)
|
||||
{
|
||||
MessageBox.Show($"Following files could not be converted:\n{string.Join("\n", failedFiles)}", "CSB Builder", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -172,6 +172,6 @@
|
||||
<value>17, 95</value>
|
||||
</metadata>
|
||||
<metadata name="$this.TrayHeight" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>172</value>
|
||||
<value>74</value>
|
||||
</metadata>
|
||||
</root>
|
@ -4,7 +4,7 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
|
||||
using CsbBuilder.BuilderNode;
|
||||
using CsbBuilder.BuilderNodes;
|
||||
|
||||
using System.Xml.Serialization;
|
||||
using System.Windows.Forms;
|
||||
|
@ -50,9 +50,8 @@ namespace CsbBuilder
|
||||
{
|
||||
using (OpenFileDialog openAdx = new OpenFileDialog
|
||||
{
|
||||
Title = "Please select your ADX file.",
|
||||
Filter = "ADX Files|*.adx",
|
||||
DefaultExt = "adx",
|
||||
Title = "Select Your Audio File",
|
||||
Filter = "All Files|*.adx;*.wav|ADX Files|*.adx|WAV Files|*.wav",
|
||||
})
|
||||
{
|
||||
if (openAdx.ShowDialog() == DialogResult.OK)
|
||||
@ -66,9 +65,8 @@ namespace CsbBuilder
|
||||
{
|
||||
using (OpenFileDialog openAdx = new OpenFileDialog
|
||||
{
|
||||
Title = "Please select your ADX file.",
|
||||
Filter = "ADX Files|*.adx",
|
||||
DefaultExt = "adx",
|
||||
Title = "Select Your Audio File",
|
||||
Filter = "All Files|*.adx;*.wav|ADX Files|*.adx|WAV Files|*.wav",
|
||||
})
|
||||
{
|
||||
if (openAdx.ShowDialog() == DialogResult.OK)
|
||||
@ -88,9 +86,12 @@ namespace CsbBuilder
|
||||
e.Cancel = true;
|
||||
}
|
||||
|
||||
if ((!string.IsNullOrEmpty(Intro) && !Intro.EndsWith(".adx")) || (!string.IsNullOrEmpty(Loop) && !Loop.EndsWith(".adx")))
|
||||
string introExtension = Path.GetExtension(Intro);
|
||||
string loopExtension = Path.GetExtension(Loop);
|
||||
|
||||
if (!string.IsNullOrEmpty(Intro) && !string.IsNullOrEmpty(Loop) && !introExtension.Equals(loopExtension, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
MessageBox.Show("Please use an .ADX file.", "CSB Builder", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||||
MessageBox.Show("Please use the same types of audio files for Intro and Loop.", "CSB Builder", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||||
e.Cancel = true;
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using CsbBuilder.BuilderNode;
|
||||
using CsbBuilder.BuilderNodes;
|
||||
|
||||
namespace CsbBuilder
|
||||
{
|
||||
|
@ -19,6 +19,14 @@ namespace CsbBuilder.Project
|
||||
DirectoryOfCsb,
|
||||
}
|
||||
|
||||
public enum NAudioWavePlayer
|
||||
{
|
||||
WaveOut,
|
||||
WasapiOut,
|
||||
DirectSoundOut,
|
||||
AsioOut,
|
||||
}
|
||||
|
||||
[DisplayName("Name node after its parent"), Category("General")]
|
||||
[Description("Names a node after its parent if it exists, or the node tree name.")]
|
||||
public bool NameNodeAfterParent { get; set; }
|
||||
@ -48,7 +56,23 @@ namespace CsbBuilder.Project
|
||||
|
||||
[DisplayName("Maximum amount of cores"), Category("Stream")]
|
||||
[Description("Maximum amount of threads used to extract data from CSB/CPK files during importing.")]
|
||||
public int MaxCores { get; set; }
|
||||
public int MaxThreads { get; set; }
|
||||
|
||||
[DisplayName("Wave Player"), Category("Sound")]
|
||||
[Description("Sound device for audio playback. If not supported, application is going to crash.")]
|
||||
public NAudioWavePlayer WavePlayer { get; set; }
|
||||
|
||||
[DisplayName("Loop Count"), Category("Audio Converter")]
|
||||
[Description("Count of loop times for audio converter if input audio has loop information.")]
|
||||
public int LoopCount { get; set; }
|
||||
|
||||
[DisplayName("Fade Out Time"), Category("Audio Converter")]
|
||||
[Description("Fade out time in seconds after total 'Loop Count' loops for audio with loop information.")]
|
||||
public double FadeTime { get; set; }
|
||||
|
||||
[DisplayName("Fade Out Delay Time"), Category("Audio Converter")]
|
||||
[Description("Delay time in seconds before audio starts to fade out.")]
|
||||
public double FadeDelay { get; set; }
|
||||
|
||||
public static Settings Load()
|
||||
{
|
||||
@ -57,7 +81,7 @@ namespace CsbBuilder.Project
|
||||
Settings settings = null;
|
||||
|
||||
if (File.Exists(path))
|
||||
{
|
||||
{
|
||||
XmlSerializer serializer = new XmlSerializer(typeof(Settings));
|
||||
|
||||
using (Stream source = File.OpenRead(path))
|
||||
@ -92,6 +116,7 @@ namespace CsbBuilder.Project
|
||||
|
||||
public Settings()
|
||||
{
|
||||
WavePlayer = NAudioWavePlayer.WaveOut;
|
||||
NameNodeAfterParent = true;
|
||||
BufferSize = 4096;
|
||||
ProjectsDirectory = "Projects";
|
||||
@ -99,7 +124,10 @@ namespace CsbBuilder.Project
|
||||
ImportedCsbProjectDirectory = ProjectDirectory.DirectoryOfCsb;
|
||||
RenameToSoundElement = true;
|
||||
EnableThreading = true;
|
||||
MaxCores = 4;
|
||||
MaxThreads = 4;
|
||||
LoopCount = 2;
|
||||
FadeTime = 10;
|
||||
FadeDelay = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<configSections>
|
||||
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
|
||||
<section name="CsbEditor.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
|
||||
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<section name="CsbEditor.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false"/>
|
||||
</sectionGroup>
|
||||
</configSections>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1"/>
|
||||
</startup>
|
||||
<userSettings>
|
||||
<CsbEditor.Properties.Settings>
|
||||
@ -21,4 +21,4 @@
|
||||
</setting>
|
||||
</CsbEditor.Properties.Settings>
|
||||
</userSettings>
|
||||
</configuration>
|
||||
</configuration>
|
||||
|
@ -9,9 +9,10 @@
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>CsbEditor</RootNamespace>
|
||||
<AssemblyName>CsbEditor</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
@ -22,6 +23,7 @@
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
|
@ -9,7 +9,7 @@ using CsbEditor.Properties;
|
||||
using SonicAudioLib;
|
||||
using SonicAudioLib.CriMw;
|
||||
using SonicAudioLib.IO;
|
||||
using SonicAudioLib.Archive;
|
||||
using SonicAudioLib.Archives;
|
||||
|
||||
using System.Globalization;
|
||||
|
||||
@ -19,6 +19,8 @@ namespace CsbEditor
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
Settings.Default.Save();
|
||||
|
||||
if (args.Length < 1)
|
||||
{
|
||||
Console.WriteLine(Resources.Description);
|
||||
@ -53,7 +55,7 @@ namespace CsbEditor
|
||||
if (reader.GetString("name") == "SOUND_ELEMENT")
|
||||
{
|
||||
long tablePosition = reader.GetPosition("utf");
|
||||
using (CriTableReader sdlReader = CriTableReader.Create(reader.GetSubstream("utf")))
|
||||
using (CriTableReader sdlReader = CriTableReader.Create(reader.GetSubStream("utf")))
|
||||
{
|
||||
while (sdlReader.Read())
|
||||
{
|
||||
@ -105,7 +107,7 @@ namespace CsbEditor
|
||||
else
|
||||
{
|
||||
long aaxPosition = sdlReader.GetPosition("data");
|
||||
using (Stream aaxSource = sdlReader.GetSubstream("data"))
|
||||
using (Stream aaxSource = sdlReader.GetSubStream("data"))
|
||||
{
|
||||
aaxArchive.Read(aaxSource);
|
||||
|
||||
@ -243,8 +245,8 @@ namespace CsbEditor
|
||||
using (Stream source = fileInfo.OpenRead())
|
||||
{
|
||||
source.Seek(7, SeekOrigin.Begin);
|
||||
numberChannels = EndianStream.ReadByte(source);
|
||||
sampleRate = EndianStream.ReadUInt32BE(source);
|
||||
numberChannels = DataStream.ReadByte(source);
|
||||
sampleRate = DataStream.ReadUInt32BE(source);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1"/>
|
||||
</startup>
|
||||
</configuration>
|
||||
</configuration>
|
||||
|
@ -7,12 +7,13 @@ using System.IO;
|
||||
using System.IO.Compression;
|
||||
|
||||
using SonicAudioLib;
|
||||
using SonicAudioLib.Archive;
|
||||
using SonicAudioLib.Archives;
|
||||
using SonicAudioLib.IO;
|
||||
using SonicAudioLib.CriMw;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using System.Xml;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace SonicAudioCmd
|
||||
{
|
||||
@ -20,48 +21,26 @@ namespace SonicAudioCmd
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
try
|
||||
using (Stream source = File.OpenRead(args[0]))
|
||||
{
|
||||
var extractor = new DataExtractor();
|
||||
extractor.ProgressChanged += OnProgressChanged;
|
||||
CriTableReader reader = CriTableReader.Create(source);
|
||||
reader.MoveToRow(3);
|
||||
|
||||
CriCpkArchive archive = new CriCpkArchive();
|
||||
archive.Load(args[0]);
|
||||
long pos = reader.GetPosition("utf");
|
||||
CriTableReader soundElementReader = reader.GetTableReader("utf");
|
||||
|
||||
foreach (CriCpkEntry entry in archive)
|
||||
while (soundElementReader.Read())
|
||||
{
|
||||
extractor.Add(args[0], Path.Combine(Path.ChangeExtension(args[0], null), entry.DirectoryName, entry.Name), entry.Position, entry.Length, entry.IsCompressed);
|
||||
CriTable table = new CriTable();
|
||||
table.Read(soundElementReader.GetSubStream("data"));
|
||||
|
||||
using (Stream output = File.Create(Path.GetFileName(soundElementReader.GetString("name") + "_" + table.Rows[0].GetValue<byte>("lpflg") + "_" + ".dsp")))
|
||||
{
|
||||
DataStream.WriteBytes(output, table.Rows[0].GetValue<byte[]>("header"));
|
||||
DataStream.WriteBytes(output, table.Rows[0].GetValue<byte[]>("data"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DateTime dateTime = DateTime.Now;
|
||||
extractor.Run();
|
||||
|
||||
Console.WriteLine("Elapsed time: {0}", DateTime.Now - dateTime);
|
||||
Console.ReadLine();
|
||||
|
||||
/*archive.EnableMask = true;
|
||||
archive.Save("test.cpk");*/
|
||||
}
|
||||
|
||||
catch (Exception exception)
|
||||
{
|
||||
Console.WriteLine(exception);
|
||||
Console.ReadLine();
|
||||
}
|
||||
}
|
||||
|
||||
private static string buffer = new string(' ', 17);
|
||||
|
||||
private static void OnProgressChanged(object sender, ProgressChangedEventArgs e)
|
||||
{
|
||||
int left = Console.CursorLeft;
|
||||
int top = Console.CursorTop;
|
||||
|
||||
Console.Write(buffer);
|
||||
Console.SetCursorPosition(left, top);
|
||||
Console.WriteLine("Progress: {0}%", e.Progress);
|
||||
Console.SetCursorPosition(left, top);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,9 +9,10 @@
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>SonicAudioCmd</RootNamespace>
|
||||
<AssemblyName>SonicAudioCmd</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
@ -22,6 +23,7 @@
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
|
@ -1,74 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
|
||||
using SonicAudioLib.Archive;
|
||||
using SonicAudioLib.IO;
|
||||
using SonicAudioLib.CriMw;
|
||||
using SonicAudioLib.Module;
|
||||
|
||||
namespace SonicAudioLib.Archive
|
||||
{
|
||||
public enum CriAaxEntryFlag
|
||||
{
|
||||
Intro = 0,
|
||||
Loop = 1,
|
||||
}
|
||||
|
||||
public class CriAaxEntry : EntryBase
|
||||
{
|
||||
public CriAaxEntryFlag Flag { get; set; }
|
||||
}
|
||||
|
||||
public class CriAaxArchive : ArchiveBase<CriAaxEntry>
|
||||
{
|
||||
public override void Read(Stream source)
|
||||
{
|
||||
using (CriTableReader reader = CriTableReader.Create(source))
|
||||
{
|
||||
if (reader.TableName != "AAX")
|
||||
{
|
||||
throw new Exception("Unknown AAX type. Please report the error with the file.");
|
||||
}
|
||||
|
||||
while (reader.Read())
|
||||
{
|
||||
CriAaxEntry entry = new CriAaxEntry();
|
||||
entry.Flag = (CriAaxEntryFlag)reader.GetByte("lpflg");
|
||||
entry.Position = reader.GetPosition("data");
|
||||
entry.Length = reader.GetLength("data");
|
||||
entries.Add(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Write(Stream destination)
|
||||
{
|
||||
using (CriTableWriter writer = CriTableWriter.Create(destination, CriTableWriterSettings.AdxSettings))
|
||||
{
|
||||
writer.WriteStartTable("AAX");
|
||||
writer.WriteField("data", typeof(byte[]));
|
||||
writer.WriteField("lpflg", typeof(byte));
|
||||
|
||||
foreach (CriAaxEntry entry in entries.OrderBy(entry => entry.Flag))
|
||||
{
|
||||
writer.WriteRow(true, entry.FilePath, (byte)entry.Flag);
|
||||
}
|
||||
|
||||
writer.WriteEndTable();
|
||||
}
|
||||
}
|
||||
|
||||
public override void Add(CriAaxEntry item)
|
||||
{
|
||||
if (entries.Count == 2 || entries.Exists(entry => (entry.Flag == item.Flag)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
base.Add(item);
|
||||
}
|
||||
}
|
||||
}
|
@ -6,10 +6,10 @@ using System.IO;
|
||||
using System.Reflection;
|
||||
|
||||
using SonicAudioLib.IO;
|
||||
using SonicAudioLib.Module;
|
||||
using SonicAudioLib.FileBases;
|
||||
using System.Collections;
|
||||
|
||||
namespace SonicAudioLib.Archive
|
||||
namespace SonicAudioLib.Archives
|
||||
{
|
||||
public abstract class EntryBase
|
||||
{
|
||||
@ -39,7 +39,7 @@ namespace SonicAudioLib.Archive
|
||||
|
||||
public virtual Stream Open(Stream source)
|
||||
{
|
||||
return new Substream(source, Position, length);
|
||||
return new SubStream(source, Position, length);
|
||||
}
|
||||
|
||||
public virtual Stream Open()
|
||||
@ -48,20 +48,10 @@ namespace SonicAudioLib.Archive
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class ArchiveBase<T> : ModuleBase, IEnumerable<T>
|
||||
public abstract class ArchiveBase<T> : FileBase, IList<T>
|
||||
{
|
||||
protected List<T> entries = new List<T>();
|
||||
|
||||
public virtual event ProgressChanged ProgressChanged;
|
||||
|
||||
public virtual T this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
return entries[index];
|
||||
}
|
||||
}
|
||||
|
||||
public virtual int Count
|
||||
{
|
||||
get
|
||||
@ -70,16 +60,49 @@ namespace SonicAudioLib.Archive
|
||||
}
|
||||
}
|
||||
|
||||
public virtual bool IsReadOnly
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual T this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
return entries[index];
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
entries[index] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual event ProgressChanged ProgressChanged;
|
||||
|
||||
public virtual int IndexOf(T item)
|
||||
{
|
||||
return entries.IndexOf(item);
|
||||
}
|
||||
|
||||
public virtual void Insert(int index, T item)
|
||||
{
|
||||
entries.Insert(index, item);
|
||||
}
|
||||
|
||||
public virtual void RemoveAt(int index)
|
||||
{
|
||||
entries.RemoveAt(index);
|
||||
}
|
||||
|
||||
public virtual void Add(T item)
|
||||
{
|
||||
entries.Add(item);
|
||||
}
|
||||
|
||||
public virtual T Get(int index)
|
||||
{
|
||||
return entries[index];
|
||||
}
|
||||
|
||||
public virtual void Clear()
|
||||
{
|
||||
entries.Clear();
|
||||
@ -95,28 +118,28 @@ namespace SonicAudioLib.Archive
|
||||
entries.CopyTo(array, arrayIndex);
|
||||
}
|
||||
|
||||
public virtual IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
return entries.GetEnumerator();
|
||||
}
|
||||
|
||||
public virtual bool Remove(T item)
|
||||
{
|
||||
return entries.Remove(item);
|
||||
}
|
||||
|
||||
public virtual IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
return entries.GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return entries.GetEnumerator();
|
||||
}
|
||||
|
||||
protected void OnProgressChanged(object sender, ProgressChangedEventArgs e)
|
||||
protected virtual void OnProgressChanged(object sender, ProgressChangedEventArgs e)
|
||||
{
|
||||
ProgressChanged?.Invoke(this, e);
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
public void Print()
|
||||
public virtual void Print()
|
||||
{
|
||||
Type archiveType = GetType();
|
||||
Console.WriteLine("{0}:", archiveType.Name);
|
167
Source/SonicAudioLib/Archives/CriAaxArchive.cs
Normal file
167
Source/SonicAudioLib/Archives/CriAaxArchive.cs
Normal file
@ -0,0 +1,167 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
|
||||
using SonicAudioLib.Archives;
|
||||
using SonicAudioLib.IO;
|
||||
using SonicAudioLib.CriMw;
|
||||
using SonicAudioLib.FileBases;
|
||||
|
||||
namespace SonicAudioLib.Archives
|
||||
{
|
||||
public enum CriAaxEntryFlag
|
||||
{
|
||||
Intro = 0,
|
||||
Loop = 1,
|
||||
}
|
||||
|
||||
public enum CriAaxArchiveMode
|
||||
{
|
||||
Adx = 0,
|
||||
Dsp = 4,
|
||||
Wav = 5,
|
||||
}
|
||||
|
||||
public class CriAaxEntry : EntryBase
|
||||
{
|
||||
public CriAaxEntryFlag Flag { get; set; }
|
||||
|
||||
// DSP
|
||||
public byte[] DspHeader { get; set; }
|
||||
public uint DspSampleRate { get; set; }
|
||||
public uint DspSampleCount { get; set; }
|
||||
public byte DspChannelCount { get; set; }
|
||||
}
|
||||
|
||||
public class CriAaxArchive : ArchiveBase<CriAaxEntry>
|
||||
{
|
||||
public CriAaxArchiveMode Mode { get; set; }
|
||||
|
||||
public override void Read(Stream source)
|
||||
{
|
||||
using (CriTableReader reader = CriTableReader.Create(source))
|
||||
{
|
||||
switch (reader.TableName)
|
||||
{
|
||||
// ADX wrapper
|
||||
case "AAX":
|
||||
Mode = CriAaxArchiveMode.Adx;
|
||||
break;
|
||||
|
||||
// DSP wrapper
|
||||
case "ADPCM_WII":
|
||||
Mode = CriAaxArchiveMode.Dsp;
|
||||
break;
|
||||
|
||||
// WAV wrapper
|
||||
case "SWLPCM":
|
||||
Mode = CriAaxArchiveMode.Wav;
|
||||
break;
|
||||
|
||||
// Unknown
|
||||
default:
|
||||
throw new InvalidDataException($"Unknown AAX type '{reader.TableName}'. Please report the error with the file(s).");
|
||||
}
|
||||
|
||||
if (Mode == CriAaxArchiveMode.Dsp)
|
||||
{
|
||||
// TODO
|
||||
throw new NotImplementedException("DSP files aren't supported yet.");
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
CriAaxEntry entry = new CriAaxEntry();
|
||||
entry.Flag = (CriAaxEntryFlag)reader.GetByte("lpflg");
|
||||
entry.Position = reader.GetPosition("data");
|
||||
entry.Length = reader.GetLength("data");
|
||||
entries.Add(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Write(Stream destination)
|
||||
{
|
||||
using (CriTableWriter writer = CriTableWriter.Create(destination, CriTableWriterSettings.AdxSettings))
|
||||
{
|
||||
string tableName = "AAX";
|
||||
|
||||
switch (Mode)
|
||||
{
|
||||
case CriAaxArchiveMode.Adx:
|
||||
tableName = "AAX";
|
||||
break;
|
||||
|
||||
case CriAaxArchiveMode.Dsp:
|
||||
tableName = "ADPCM_WII";
|
||||
break;
|
||||
|
||||
case CriAaxArchiveMode.Wav:
|
||||
tableName = "SWLPCM";
|
||||
break;
|
||||
}
|
||||
|
||||
writer.WriteStartTable(tableName);
|
||||
writer.WriteField("data", typeof(byte[]));
|
||||
writer.WriteField("lpflg", typeof(byte));
|
||||
|
||||
foreach (CriAaxEntry entry in entries.OrderBy(entry => entry.Flag))
|
||||
{
|
||||
writer.WriteRow(true, entry.FilePath, (byte)entry.Flag);
|
||||
}
|
||||
|
||||
writer.WriteEndTable();
|
||||
}
|
||||
}
|
||||
|
||||
public override void Add(CriAaxEntry item)
|
||||
{
|
||||
if (entries.Count == 2 || entries.Exists(entry => (entry.Flag == item.Flag)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
base.Add(item);
|
||||
}
|
||||
|
||||
public string GetModeExtension()
|
||||
{
|
||||
switch (Mode)
|
||||
{
|
||||
case CriAaxArchiveMode.Adx:
|
||||
return ".adx";
|
||||
|
||||
case CriAaxArchiveMode.Dsp:
|
||||
return ".dsp";
|
||||
|
||||
case CriAaxArchiveMode.Wav:
|
||||
return ".wav";
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
public void SetModeFromExtension(string extension)
|
||||
{
|
||||
switch (Path.GetExtension(extension).ToLower())
|
||||
{
|
||||
case ".adx":
|
||||
Mode = CriAaxArchiveMode.Adx;
|
||||
break;
|
||||
|
||||
case ".dsp":
|
||||
Mode = CriAaxArchiveMode.Dsp;
|
||||
break;
|
||||
|
||||
case ".wav":
|
||||
Mode = CriAaxArchiveMode.Wav;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -6,9 +6,9 @@ using System.IO;
|
||||
using System.Diagnostics;
|
||||
|
||||
using SonicAudioLib.IO;
|
||||
using SonicAudioLib.Module;
|
||||
using SonicAudioLib.FileBases;
|
||||
|
||||
namespace SonicAudioLib.Archive
|
||||
namespace SonicAudioLib.Archives
|
||||
{
|
||||
public class CriAfs2Entry : EntryBase
|
||||
{
|
||||
@ -32,25 +32,25 @@ namespace SonicAudioLib.Archive
|
||||
switch (length)
|
||||
{
|
||||
case 2:
|
||||
return EndianStream.ReadUInt16(source);
|
||||
return DataStream.ReadUInt16(source);
|
||||
|
||||
case 4:
|
||||
return EndianStream.ReadUInt32(source);
|
||||
return DataStream.ReadUInt32(source);
|
||||
|
||||
case 8:
|
||||
return EndianStream.ReadInt64(source);
|
||||
return DataStream.ReadInt64(source);
|
||||
|
||||
default:
|
||||
throw new ArgumentException($"Unimplemented field length ({length})", nameof(length));
|
||||
}
|
||||
}
|
||||
|
||||
if (EndianStream.ReadCString(source, 4) != "AFS2")
|
||||
if (DataStream.ReadCString(source, 4) != "AFS2")
|
||||
{
|
||||
throw new InvalidDataException("'AFS2' signature could not be found.");
|
||||
}
|
||||
|
||||
uint information = EndianStream.ReadUInt32(source);
|
||||
uint information = DataStream.ReadUInt32(source);
|
||||
|
||||
uint type = information & 0xFF;
|
||||
if (type != 1)
|
||||
@ -61,8 +61,8 @@ namespace SonicAudioLib.Archive
|
||||
uint idFieldLength = (information >> 16) & 0xFF;
|
||||
uint positionFieldLength = (information >> 8) & 0xFF;
|
||||
|
||||
uint entryCount = EndianStream.ReadUInt32(source);
|
||||
Align = EndianStream.ReadUInt32(source);
|
||||
uint entryCount = DataStream.ReadUInt32(source);
|
||||
Align = DataStream.ReadUInt32(source);
|
||||
|
||||
CriAfs2Entry previousEntry = null;
|
||||
for (uint i = 0; i < entryCount; i++)
|
||||
@ -138,15 +138,15 @@ namespace SonicAudioLib.Archive
|
||||
switch (length)
|
||||
{
|
||||
case 2:
|
||||
EndianStream.WriteUInt16(mDestination, (ushort)value);
|
||||
DataStream.WriteUInt16(mDestination, (ushort)value);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
EndianStream.WriteUInt32(mDestination, (uint)value);
|
||||
DataStream.WriteUInt32(mDestination, (uint)value);
|
||||
break;
|
||||
|
||||
case 8:
|
||||
EndianStream.WriteInt64(mDestination, value);
|
||||
DataStream.WriteInt64(mDestination, value);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -156,12 +156,12 @@ namespace SonicAudioLib.Archive
|
||||
|
||||
long headerLength = Calculate(out uint idFieldLength, out uint positionFieldLength);
|
||||
|
||||
EndianStream.WriteCString(mDestination, "AFS2", 4);
|
||||
EndianStream.WriteUInt32(mDestination, 1 | (idFieldLength << 16) | (positionFieldLength << 8));
|
||||
EndianStream.WriteUInt32(mDestination, (uint)entries.Count);
|
||||
EndianStream.WriteUInt32(mDestination, Align);
|
||||
DataStream.WriteCString(mDestination, "AFS2", 4);
|
||||
DataStream.WriteUInt32(mDestination, 1 | (idFieldLength << 16) | (positionFieldLength << 8));
|
||||
DataStream.WriteUInt32(mDestination, (uint)entries.Count);
|
||||
DataStream.WriteUInt32(mDestination, Align);
|
||||
|
||||
VldPool vldPool = new VldPool(Align, headerLength);
|
||||
DataPool vldPool = new DataPool(Align, headerLength);
|
||||
vldPool.ProgressChanged += OnProgressChanged;
|
||||
|
||||
var orderedEntries = entries.OrderBy(entry => entry.Id);
|
@ -8,7 +8,7 @@ using System.Reflection;
|
||||
using SonicAudioLib.IO;
|
||||
using SonicAudioLib.CriMw;
|
||||
|
||||
namespace SonicAudioLib.Archive
|
||||
namespace SonicAudioLib.Archives
|
||||
{
|
||||
public class CriCpkEntry : EntryBase
|
||||
{
|
||||
@ -19,6 +19,7 @@ namespace SonicAudioLib.Archive
|
||||
public uint Id { get; set; }
|
||||
public string Comment { get; set; }
|
||||
public bool IsCompressed { get; set; }
|
||||
public long UncompressedLength { get; set; }
|
||||
|
||||
public DateTime UpdateDateTime
|
||||
{
|
||||
@ -67,7 +68,7 @@ namespace SonicAudioLib.Archive
|
||||
{
|
||||
if (align != 1)
|
||||
{
|
||||
new NotImplementedException("Alignment is currently not implemented.");
|
||||
throw new NotImplementedException("Alignment is currently not implemented.");
|
||||
}
|
||||
|
||||
align = value;
|
||||
@ -168,7 +169,8 @@ namespace SonicAudioLib.Archive
|
||||
entry.Position = (long)tocReader.GetUInt64("FileOffset");
|
||||
entry.Id = isLatestVersion ? tocReader.GetUInt32("ID") : tocReader.GetUInt32("Info");
|
||||
entry.Comment = tocReader.GetString("UserString");
|
||||
entry.IsCompressed = entry.Length != tocReader.GetUInt32("ExtractSize");
|
||||
entry.UncompressedLength = tocReader.GetUInt32("ExtractSize");
|
||||
entry.IsCompressed = entry.Length != entry.UncompressedLength;
|
||||
|
||||
if (contentPosition < tocPosition)
|
||||
{
|
||||
@ -209,14 +211,15 @@ namespace SonicAudioLib.Archive
|
||||
{
|
||||
if (itocReader.GetUInt32("FilesL") > 0)
|
||||
{
|
||||
using (CriTableReader dataReader = itocReader.GetCriTableReader("DataL"))
|
||||
using (CriTableReader dataReader = itocReader.GetTableReader("DataL"))
|
||||
{
|
||||
while (dataReader.Read())
|
||||
{
|
||||
CriCpkEntry entry = new CriCpkEntry();
|
||||
entry.Id = dataReader.GetUInt16("ID");
|
||||
entry.Length = dataReader.GetUInt16("FileSize");
|
||||
entry.IsCompressed = entry.Length != dataReader.GetUInt16("ExtractSize");
|
||||
entry.UncompressedLength = dataReader.GetUInt16("ExtractSize");
|
||||
entry.IsCompressed = entry.Length != entry.UncompressedLength;
|
||||
|
||||
entries.Add(entry);
|
||||
}
|
||||
@ -225,14 +228,15 @@ namespace SonicAudioLib.Archive
|
||||
|
||||
if (itocReader.GetUInt32("FilesH") > 0)
|
||||
{
|
||||
using (CriTableReader dataReader = itocReader.GetCriTableReader("DataH"))
|
||||
using (CriTableReader dataReader = itocReader.GetTableReader("DataH"))
|
||||
{
|
||||
while (dataReader.Read())
|
||||
{
|
||||
CriCpkEntry entry = new CriCpkEntry();
|
||||
entry.Id = dataReader.GetUInt16("ID");
|
||||
entry.Length = dataReader.GetUInt32("FileSize");
|
||||
entry.IsCompressed = entry.Length != dataReader.GetUInt32("ExtractSize");
|
||||
entry.UncompressedLength = dataReader.GetUInt32("ExtractSize");
|
||||
entry.IsCompressed = entry.Length != entry.UncompressedLength;
|
||||
|
||||
entries.Add(entry);
|
||||
}
|
||||
@ -268,7 +272,7 @@ namespace SonicAudioLib.Archive
|
||||
return $"{assemblyName.Name}, {assemblyName.Version.ToString()}";
|
||||
}
|
||||
|
||||
VldPool vldPool = new VldPool(Align, 2048);
|
||||
DataPool vldPool = new DataPool(Align, 2048);
|
||||
vldPool.ProgressChanged += OnProgressChanged;
|
||||
|
||||
using (CriCpkSection cpkSection = new CriCpkSection(destination, "CPK ", enableMask))
|
||||
@ -553,8 +557,8 @@ namespace SonicAudioLib.Archive
|
||||
cpkSection.Writer.WriteEndTable();
|
||||
}
|
||||
|
||||
EndianStream.Pad(destination, 2042);
|
||||
EndianStream.WriteCString(destination, "(c)CRI", 6);
|
||||
DataStream.Pad(destination, 2042);
|
||||
DataStream.WriteCString(destination, "(c)CRI", 6);
|
||||
|
||||
vldPool.Write(destination);
|
||||
}
|
||||
@ -587,97 +591,80 @@ namespace SonicAudioLib.Archive
|
||||
});
|
||||
}
|
||||
|
||||
public static void Decompress(Stream source, long position, Stream destination)
|
||||
public static void Decompress(byte[] source, byte[] destination)
|
||||
{
|
||||
source.Position = position;
|
||||
|
||||
if (EndianStream.ReadCString(source, 8) != "CRILAYLA")
|
||||
if (Encoding.ASCII.GetString(source, 0, 8) != "CRILAYLA")
|
||||
{
|
||||
throw new InvalidDataException("'CRILAYLA' signature could not be found.");
|
||||
}
|
||||
|
||||
uint uncompressedLength = EndianStream.ReadUInt32(source);
|
||||
uint compressedLength = EndianStream.ReadUInt32(source);
|
||||
int uncompressedLength = BitConverter.ToInt32(source, 8);
|
||||
int compressedLength = BitConverter.ToInt32(source, 12);
|
||||
|
||||
// Copy the uncompressed header to destination
|
||||
EndianStream.CopyPartTo(source, destination, position + 0x10 + compressedLength, 0x100, 4096);
|
||||
Array.Copy(source, 16 + compressedLength, destination, 0, 256);
|
||||
|
||||
int srcEnd = 16 + compressedLength - 1;
|
||||
int dstEnd = 256 + uncompressedLength - 1;
|
||||
int dstOut = 0;
|
||||
|
||||
// Bit methods
|
||||
int bitCount = 0;
|
||||
int bitData = 0;
|
||||
int bitNum = 0;
|
||||
|
||||
int ReadBits(int count)
|
||||
{
|
||||
if (bitCount < count)
|
||||
if (bitNum < count)
|
||||
{
|
||||
int neededBytes = ((24 - bitCount) >> 3) + 1;
|
||||
bitCount += neededBytes * 8;
|
||||
int byteNum = ((24 - bitNum) >> 3) + 1;
|
||||
bitNum += byteNum * 8;
|
||||
|
||||
while (neededBytes > 0)
|
||||
while (byteNum > 0)
|
||||
{
|
||||
bitData = (bitData << 8) | source.ReadByte();
|
||||
neededBytes--;
|
||||
source.Position -= 2;
|
||||
bitData = source[srcEnd--] | bitData << 8;
|
||||
byteNum--;
|
||||
}
|
||||
}
|
||||
|
||||
bitCount -= count;
|
||||
return (bitData >> bitCount) & ((1 << count) - 1);
|
||||
bitNum -= count;
|
||||
return (bitData >> bitNum) & ((1 << count) - 1);
|
||||
}
|
||||
|
||||
// Deflate levels
|
||||
IEnumerable<int> GetDeflateLevels()
|
||||
while (dstOut < uncompressedLength)
|
||||
{
|
||||
yield return 2;
|
||||
yield return 3;
|
||||
yield return 5;
|
||||
|
||||
while (true)
|
||||
if (ReadBits(1) != 0)
|
||||
{
|
||||
yield return 8;
|
||||
}
|
||||
}
|
||||
int position = dstEnd - dstOut + ReadBits(13) + 3;
|
||||
int length = 3 + ReadBits(2);
|
||||
|
||||
// Decompression
|
||||
source.Position = position + 0x10 + compressedLength - 1;
|
||||
|
||||
long writtenBytes = 0;
|
||||
byte[] buffer = new byte[uncompressedLength];
|
||||
|
||||
while (writtenBytes < uncompressedLength)
|
||||
{
|
||||
// Verbatim byte, directly copy
|
||||
if (ReadBits(1) == 0)
|
||||
{
|
||||
buffer[uncompressedLength - (writtenBytes++) - 1] = (byte)ReadBits(8);
|
||||
}
|
||||
|
||||
// Referenced bytes
|
||||
else
|
||||
{
|
||||
long pos = uncompressedLength - 1 - writtenBytes + ReadBits(13) + 3;
|
||||
long length = 3;
|
||||
|
||||
foreach (var deflateLevel in GetDeflateLevels())
|
||||
if (length == 3 + 3)
|
||||
{
|
||||
long len = ReadBits(deflateLevel);
|
||||
length += len;
|
||||
length += ReadBits(3);
|
||||
|
||||
if (len != ((1 << deflateLevel) - 1))
|
||||
if (length == 3 + 3 + 7)
|
||||
{
|
||||
break;
|
||||
length += ReadBits(5);
|
||||
|
||||
if (length == 3 + 3 + 7 + 31)
|
||||
{
|
||||
int bits;
|
||||
|
||||
do
|
||||
{
|
||||
bits = ReadBits(8);
|
||||
length += bits;
|
||||
} while (bits == 255);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (length > 0)
|
||||
{
|
||||
buffer[uncompressedLength - 1 - (writtenBytes++)] = buffer[pos--];
|
||||
length--;
|
||||
}
|
||||
dstOut += length;
|
||||
Array.Copy(destination, position - length + 1, destination, dstEnd - dstOut + 1, length);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
destination[dstEnd - dstOut++] = (byte)ReadBits(8);
|
||||
}
|
||||
}
|
||||
|
||||
destination.Write(buffer, 0, buffer.Length);
|
||||
}
|
||||
|
||||
private DateTime DateTimeFromCpkDateTime(ulong dateTime)
|
||||
@ -727,7 +714,7 @@ namespace SonicAudioLib.Archive
|
||||
uint length = (uint)(position - (headerPosition) - 16);
|
||||
|
||||
destination.Seek(headerPosition + 8, SeekOrigin.Begin);
|
||||
EndianStream.WriteUInt32(destination, length);
|
||||
DataStream.WriteUInt32(destination, length);
|
||||
|
||||
destination.Seek(position, SeekOrigin.Begin);
|
||||
}
|
||||
@ -736,16 +723,16 @@ namespace SonicAudioLib.Archive
|
||||
{
|
||||
source.Seek(position, SeekOrigin.Begin);
|
||||
|
||||
if (EndianStream.ReadCString(source, 4) != expectedSignature)
|
||||
if (DataStream.ReadCString(source, 4) != expectedSignature)
|
||||
{
|
||||
throw new InvalidDataException($"'{expectedSignature}' signature could not be found.");
|
||||
}
|
||||
|
||||
uint flag = EndianStream.ReadUInt32(source);
|
||||
uint tableLength = EndianStream.ReadUInt32(source);
|
||||
uint unknown = EndianStream.ReadUInt32(source);
|
||||
uint flag = DataStream.ReadUInt32(source);
|
||||
uint tableLength = DataStream.ReadUInt32(source);
|
||||
uint unknown = DataStream.ReadUInt32(source);
|
||||
|
||||
return CriTableReader.Create(new Substream(source, source.Position, tableLength));
|
||||
return CriTableReader.Create(new SubStream(source, source.Position, tableLength));
|
||||
}
|
||||
|
||||
public CriCpkSection(Stream destination, string signature, bool enableMask)
|
||||
@ -753,11 +740,17 @@ namespace SonicAudioLib.Archive
|
||||
this.destination = destination;
|
||||
headerPosition = destination.Position;
|
||||
|
||||
EndianStream.WriteCString(destination, signature, 4);
|
||||
EndianStream.WriteUInt32(destination, 0xFF);
|
||||
DataStream.WriteCString(destination, signature, 4);
|
||||
DataStream.WriteUInt32(destination, 0xFF);
|
||||
destination.Seek(8, SeekOrigin.Current);
|
||||
|
||||
writer = CriTableWriter.Create(destination, new CriTableWriterSettings() { LeaveOpen = true, EnableMask = enableMask, MaskXor = 25951, MaskXorMultiplier = 16661 });
|
||||
writer = CriTableWriter.Create(destination, new CriTableWriterSettings()
|
||||
{
|
||||
LeaveOpen = true,
|
||||
EnableMask = enableMask,
|
||||
MaskXor = 25951,
|
||||
MaskXorMultiplier = 16661
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -5,9 +5,9 @@ using System.Text;
|
||||
using System.IO;
|
||||
|
||||
using SonicAudioLib.IO;
|
||||
using SonicAudioLib.Module;
|
||||
using SonicAudioLib.FileBases;
|
||||
|
||||
namespace SonicAudioLib.Archive
|
||||
namespace SonicAudioLib.Archives
|
||||
{
|
||||
public class HeroesPacEntry : EntryBase
|
||||
{
|
||||
@ -18,10 +18,10 @@ namespace SonicAudioLib.Archive
|
||||
{
|
||||
public override void Read(Stream source)
|
||||
{
|
||||
uint entryCount = EndianStream.ReadUInt32(source);
|
||||
uint tablePosition = EndianStream.ReadUInt32(source);
|
||||
uint vldPoolLength = EndianStream.ReadUInt32(source);
|
||||
uint vldPoolPosition = EndianStream.ReadUInt32(source);
|
||||
uint entryCount = DataStream.ReadUInt32(source);
|
||||
uint tablePosition = DataStream.ReadUInt32(source);
|
||||
uint vldPoolLength = DataStream.ReadUInt32(source);
|
||||
uint vldPoolPosition = DataStream.ReadUInt32(source);
|
||||
|
||||
source.Seek(tablePosition, SeekOrigin.Begin);
|
||||
|
||||
@ -30,8 +30,8 @@ namespace SonicAudioLib.Archive
|
||||
{
|
||||
HeroesPacEntry pacEntry = new HeroesPacEntry();
|
||||
|
||||
pacEntry.Id = EndianStream.ReadUInt32(source);
|
||||
pacEntry.Position = vldPoolPosition + EndianStream.ReadUInt32(source);
|
||||
pacEntry.Id = DataStream.ReadUInt32(source);
|
||||
pacEntry.Position = vldPoolPosition + DataStream.ReadUInt32(source);
|
||||
|
||||
if (previousEntry != null)
|
||||
{
|
||||
@ -68,14 +68,14 @@ namespace SonicAudioLib.Archive
|
||||
uint tableLength = (uint)(entries.Count * 16);
|
||||
uint tablePosition = (uint)destination.Position;
|
||||
|
||||
VldPool vldPool = new VldPool();
|
||||
DataPool vldPool = new DataPool();
|
||||
|
||||
foreach (HeroesPacEntry pacEntry in entries)
|
||||
{
|
||||
uint entryPosition = (uint)vldPool.Put(pacEntry.FilePath);
|
||||
|
||||
EndianStream.WriteUInt32(destination, pacEntry.Id);
|
||||
EndianStream.WriteUInt32(destination, entryPosition);
|
||||
DataStream.WriteUInt32(destination, pacEntry.Id);
|
||||
DataStream.WriteUInt32(destination, entryPosition);
|
||||
|
||||
while ((destination.Position % 16) != 0)
|
||||
{
|
||||
@ -89,10 +89,10 @@ namespace SonicAudioLib.Archive
|
||||
vldPool.Clear();
|
||||
|
||||
destination.Seek(0, SeekOrigin.Begin);
|
||||
EndianStream.WriteUInt32(destination, (uint)entries.Count);
|
||||
EndianStream.WriteUInt32(destination, tablePosition);
|
||||
EndianStream.WriteUInt32(destination, (uint)vldPool.Length);
|
||||
EndianStream.WriteUInt32(destination, (uint)vldPool.Position);
|
||||
DataStream.WriteUInt32(destination, (uint)entries.Count);
|
||||
DataStream.WriteUInt32(destination, tablePosition);
|
||||
DataStream.WriteUInt32(destination, (uint)vldPool.Length);
|
||||
DataStream.WriteUInt32(destination, (uint)vldPool.Position);
|
||||
}
|
||||
}
|
||||
}
|
@ -94,6 +94,21 @@ namespace SonicAudioLib.CriMw
|
||||
}
|
||||
}
|
||||
|
||||
public T GetValue<T>(CriField criField)
|
||||
{
|
||||
return (T)this[criField];
|
||||
}
|
||||
|
||||
public T GetValue<T>(string fieldName)
|
||||
{
|
||||
return (T)this[fieldName];
|
||||
}
|
||||
|
||||
public T GetValue<T>(int fieldIndex)
|
||||
{
|
||||
return (T)this[fieldIndex];
|
||||
}
|
||||
|
||||
public object[] GetValueArray()
|
||||
{
|
||||
object[] values = new object[records.Count];
|
||||
|
@ -5,20 +5,23 @@ namespace SonicAudioLib.CriMw
|
||||
{
|
||||
struct CriTableHeader
|
||||
{
|
||||
public const string Signature = "@UTF";
|
||||
public static readonly byte[] SignatureBytes = { 0x40, 0x55, 0x54, 0x46 };
|
||||
|
||||
public const byte EncodingTypeShiftJis = 0;
|
||||
public const byte EncodingTypeUtf8 = 1;
|
||||
|
||||
public byte[] Signature;
|
||||
public uint Length;
|
||||
public byte UnknownByte;
|
||||
public byte EncodingType;
|
||||
public ushort RowsPosition;
|
||||
public uint StringPoolPosition;
|
||||
public uint DataPoolPosition;
|
||||
public uint TableNamePosition;
|
||||
public string TableName;
|
||||
public ushort NumberOfFields;
|
||||
public ushort FieldCount;
|
||||
public ushort RowLength;
|
||||
public uint NumberOfRows;
|
||||
public uint RowCount;
|
||||
}
|
||||
|
||||
[Flags]
|
||||
@ -47,6 +50,7 @@ namespace SonicAudioLib.CriMw
|
||||
|
||||
struct CriTableField
|
||||
{
|
||||
public uint Offset;
|
||||
public CriFieldFlag Flag;
|
||||
public string Name;
|
||||
public uint Position;
|
||||
@ -61,13 +65,13 @@ namespace SonicAudioLib.CriMw
|
||||
for (byte x = 0; x <= byte.MaxValue; x++)
|
||||
{
|
||||
// Find XOR using first byte
|
||||
if ((signature[0] ^ x) == CriTableHeader.Signature[0])
|
||||
if ((signature[0] ^ x) == CriTableHeader.SignatureBytes[0])
|
||||
{
|
||||
// Matched the first byte, try finding the multiplier with the second byte
|
||||
for (byte m = 0; m <= byte.MaxValue; m++)
|
||||
{
|
||||
// Matched the second byte, now make sure the other bytes match as well
|
||||
if ((signature[1] ^ (byte)(x * m)) == CriTableHeader.Signature[1])
|
||||
if ((signature[1] ^ (byte)(x * m)) == CriTableHeader.SignatureBytes[1])
|
||||
{
|
||||
byte _x = (byte)(x * m);
|
||||
|
||||
@ -76,7 +80,7 @@ namespace SonicAudioLib.CriMw
|
||||
{
|
||||
_x *= m;
|
||||
|
||||
if ((signature[i] ^ _x) != CriTableHeader.Signature[i])
|
||||
if ((signature[i] ^ _x) != CriTableHeader.SignatureBytes[i])
|
||||
{
|
||||
allMatches = false;
|
||||
break;
|
||||
|
@ -3,11 +3,13 @@ using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
using SonicAudioLib.IO;
|
||||
using SonicAudioLib.Module;
|
||||
using SonicAudioLib.FileBases;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace SonicAudioLib.CriMw
|
||||
{
|
||||
public class CriTable : ModuleBase
|
||||
public class CriTable : FileXmlBase
|
||||
{
|
||||
private CriFieldCollection fields;
|
||||
private CriRowCollection rows;
|
||||
@ -141,6 +143,86 @@ namespace SonicAudioLib.CriMw
|
||||
}
|
||||
}
|
||||
|
||||
public override void ReadXml(XmlReader reader)
|
||||
{
|
||||
var document = XDocument.Load(reader);
|
||||
|
||||
foreach (XElement element in document.Root.Element(nameof(Fields)).Elements(nameof(CriField)))
|
||||
{
|
||||
fields.Add(
|
||||
element.Element(nameof(CriField.FieldName)).Value,
|
||||
Type.GetType(element.Element(nameof(CriField.FieldType)).Value)
|
||||
);
|
||||
}
|
||||
|
||||
foreach (XElement element in document.Root.Element(nameof(Rows)).Elements(nameof(CriRow)))
|
||||
{
|
||||
CriRow row = NewRow();
|
||||
|
||||
foreach (CriRowRecord record in row.Records)
|
||||
{
|
||||
if (record.Field.FieldType == typeof(byte[]))
|
||||
{
|
||||
record.Value = Convert.FromBase64String(element.Element(record.Field.FieldName).Value);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
record.Value = Convert.ChangeType(element.Element(record.Field.FieldName).Value, record.Field.FieldType);
|
||||
}
|
||||
}
|
||||
|
||||
rows.Add(row);
|
||||
}
|
||||
}
|
||||
|
||||
public override void WriteXml(XmlWriter writer)
|
||||
{
|
||||
var document = new XDocument(new XElement(nameof(CriTable)));
|
||||
document.Root.Add(new XElement(nameof(TableName), TableName));
|
||||
|
||||
var fieldsElement = new XElement(nameof(Fields));
|
||||
|
||||
foreach (CriField field in fields)
|
||||
{
|
||||
var fieldElement = new XElement(nameof(CriField));
|
||||
|
||||
fieldElement.Add(
|
||||
new XElement(nameof(field.FieldName), field.FieldName),
|
||||
new XElement(nameof(field.FieldType), field.FieldType.Name)
|
||||
);
|
||||
|
||||
fieldsElement.Add(fieldElement);
|
||||
}
|
||||
|
||||
document.Root.Add(fieldsElement);
|
||||
|
||||
var rowsElement = new XElement(nameof(Rows));
|
||||
|
||||
foreach (CriRow row in rows)
|
||||
{
|
||||
var rowElement = new XElement(nameof(CriRow));
|
||||
|
||||
foreach (CriRowRecord record in row.Records)
|
||||
{
|
||||
if (record.Value is byte[] bytes)
|
||||
{
|
||||
rowElement.Add(new XElement(record.Field.FieldName, Convert.ToBase64String(bytes)));
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
rowElement.Add(new XElement(record.Field.FieldName, record.Value));
|
||||
}
|
||||
}
|
||||
|
||||
rowsElement.Add(rowElement);
|
||||
}
|
||||
|
||||
document.Root.Add(rowsElement);
|
||||
document.Save(writer);
|
||||
}
|
||||
|
||||
public CriTable()
|
||||
{
|
||||
fields = new CriFieldCollection(this);
|
||||
|
@ -3,6 +3,8 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Linq;
|
||||
using System.Collections;
|
||||
|
||||
namespace SonicAudioLib.CriMw
|
||||
{
|
||||
@ -13,7 +15,7 @@ namespace SonicAudioLib.CriMw
|
||||
private CriTableHeader header;
|
||||
private Encoding encoding;
|
||||
private long rowIndex = -1;
|
||||
private uint headerPosition;
|
||||
private long headerPosition;
|
||||
private bool leaveOpen;
|
||||
|
||||
public object this[int fieldIndex]
|
||||
@ -36,7 +38,7 @@ namespace SonicAudioLib.CriMw
|
||||
{
|
||||
get
|
||||
{
|
||||
return header.NumberOfFields;
|
||||
return header.FieldCount;
|
||||
}
|
||||
}
|
||||
|
||||
@ -44,7 +46,7 @@ namespace SonicAudioLib.CriMw
|
||||
{
|
||||
get
|
||||
{
|
||||
return header.NumberOfRows;
|
||||
return header.RowCount;
|
||||
}
|
||||
}
|
||||
|
||||
@ -82,16 +84,15 @@ namespace SonicAudioLib.CriMw
|
||||
|
||||
private void ReadTable()
|
||||
{
|
||||
headerPosition = (uint)source.Position;
|
||||
headerPosition = source.Position;
|
||||
|
||||
if (EndianStream.ReadCString(source, 4) != CriTableHeader.Signature)
|
||||
if (!(header.Signature = DataStream.ReadBytes(source, 4)).SequenceEqual(CriTableHeader.SignatureBytes))
|
||||
{
|
||||
MemoryStream unmaskedSource = new MemoryStream();
|
||||
|
||||
source.Position = headerPosition;
|
||||
CriTableMasker.FindKeys(EndianStream.ReadBytes(source, 4), out uint x, out uint m);
|
||||
CriTableMasker.FindKeys(header.Signature, out uint x, out uint m);
|
||||
|
||||
source.Position = headerPosition;
|
||||
source.Seek(headerPosition, SeekOrigin.Begin);
|
||||
CriTableMasker.Mask(source, unmaskedSource, source.Length, x, m);
|
||||
|
||||
// Close the old stream
|
||||
@ -101,12 +102,12 @@ namespace SonicAudioLib.CriMw
|
||||
}
|
||||
|
||||
source = unmaskedSource;
|
||||
source.Position = 4;
|
||||
source.Seek(4, SeekOrigin.Begin);
|
||||
}
|
||||
|
||||
header.Length = ReadUInt32() + 0x8;
|
||||
header.UnknownByte = ReadByte();
|
||||
header.EncodingType = ReadByte();
|
||||
header.Length = DataStream.ReadUInt32BE(source) + 0x8;
|
||||
header.UnknownByte = DataStream.ReadByte(source);
|
||||
header.EncodingType = DataStream.ReadByte(source);
|
||||
|
||||
if (header.UnknownByte != 0)
|
||||
{
|
||||
@ -127,18 +128,19 @@ namespace SonicAudioLib.CriMw
|
||||
throw new InvalidDataException($"Unknown encoding type ({header.EncodingType}). Please report this error with the file(s).");
|
||||
}
|
||||
|
||||
header.RowsPosition = (ushort)(ReadUInt16() + 0x8);
|
||||
header.StringPoolPosition = ReadUInt32() + 0x8;
|
||||
header.DataPoolPosition = ReadUInt32() + 0x8;
|
||||
header.RowsPosition = (ushort)(DataStream.ReadUInt16BE(source) + 0x8);
|
||||
header.StringPoolPosition = DataStream.ReadUInt32BE(source) + 0x8;
|
||||
header.DataPoolPosition = DataStream.ReadUInt32BE(source) + 0x8;
|
||||
header.TableName = ReadString();
|
||||
header.NumberOfFields = ReadUInt16();
|
||||
header.RowLength = ReadUInt16();
|
||||
header.NumberOfRows = ReadUInt32();
|
||||
header.FieldCount = DataStream.ReadUInt16BE(source);
|
||||
header.RowLength = DataStream.ReadUInt16BE(source);
|
||||
header.RowCount = DataStream.ReadUInt32BE(source);
|
||||
|
||||
for (ushort i = 0; i < header.NumberOfFields; i++)
|
||||
uint offset = 0;
|
||||
for (ushort i = 0; i < header.FieldCount; i++)
|
||||
{
|
||||
CriTableField field = new CriTableField();
|
||||
field.Flag = (CriFieldFlag)ReadByte();
|
||||
field.Flag = (CriFieldFlag)DataStream.ReadByte(source);
|
||||
|
||||
if (field.Flag.HasFlag(CriFieldFlag.Name))
|
||||
{
|
||||
@ -149,7 +151,8 @@ namespace SonicAudioLib.CriMw
|
||||
{
|
||||
if (field.Flag.HasFlag(CriFieldFlag.Data))
|
||||
{
|
||||
ReadData(out field.Position, out field.Length);
|
||||
field.Position = DataStream.ReadUInt32BE(source);
|
||||
field.Length = DataStream.ReadUInt32BE(source);
|
||||
}
|
||||
|
||||
else
|
||||
@ -164,6 +167,36 @@ namespace SonicAudioLib.CriMw
|
||||
field.Value = CriField.NullValues[(byte)field.Flag & 0x0F];
|
||||
}
|
||||
|
||||
// Row storage, calculate the offset
|
||||
if (field.Flag.HasFlag(CriFieldFlag.RowStorage))
|
||||
{
|
||||
field.Offset = offset;
|
||||
|
||||
switch (field.Flag & CriFieldFlag.TypeMask)
|
||||
{
|
||||
case CriFieldFlag.Byte:
|
||||
case CriFieldFlag.SByte:
|
||||
offset += 1;
|
||||
break;
|
||||
case CriFieldFlag.Int16:
|
||||
case CriFieldFlag.UInt16:
|
||||
offset += 2;
|
||||
break;
|
||||
case CriFieldFlag.Int32:
|
||||
case CriFieldFlag.UInt32:
|
||||
case CriFieldFlag.Single:
|
||||
case CriFieldFlag.String:
|
||||
offset += 4;
|
||||
break;
|
||||
case CriFieldFlag.Int64:
|
||||
case CriFieldFlag.UInt64:
|
||||
case CriFieldFlag.Double:
|
||||
case CriFieldFlag.Data:
|
||||
offset += 8;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fields.Add(field);
|
||||
}
|
||||
}
|
||||
@ -225,46 +258,12 @@ namespace SonicAudioLib.CriMw
|
||||
|
||||
private void GoToValue(int fieldIndex)
|
||||
{
|
||||
long position = headerPosition + header.RowsPosition + (header.RowLength * rowIndex);
|
||||
|
||||
for (int i = 0; i < fieldIndex; i++)
|
||||
{
|
||||
if (!fields[i].Flag.HasFlag(CriFieldFlag.RowStorage))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (fields[i].Flag & CriFieldFlag.TypeMask)
|
||||
{
|
||||
case CriFieldFlag.Byte:
|
||||
case CriFieldFlag.SByte:
|
||||
position += 1;
|
||||
break;
|
||||
case CriFieldFlag.Int16:
|
||||
case CriFieldFlag.UInt16:
|
||||
position += 2;
|
||||
break;
|
||||
case CriFieldFlag.Int32:
|
||||
case CriFieldFlag.UInt32:
|
||||
case CriFieldFlag.Single:
|
||||
case CriFieldFlag.String:
|
||||
position += 4;
|
||||
break;
|
||||
case CriFieldFlag.Int64:
|
||||
case CriFieldFlag.UInt64:
|
||||
case CriFieldFlag.Double:
|
||||
case CriFieldFlag.Data:
|
||||
position += 8;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
source.Position = position;
|
||||
source.Seek(headerPosition + header.RowsPosition + (header.RowLength * rowIndex) + fields[fieldIndex].Offset, SeekOrigin.Begin);
|
||||
}
|
||||
|
||||
public bool Read()
|
||||
{
|
||||
if (rowIndex + 1 >= header.NumberOfRows)
|
||||
if (rowIndex + 1 >= header.RowCount)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -275,7 +274,7 @@ namespace SonicAudioLib.CriMw
|
||||
|
||||
public bool MoveToRow(long rowIndex)
|
||||
{
|
||||
if (rowIndex >= header.NumberOfRows)
|
||||
if (rowIndex >= header.RowCount)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -286,9 +285,9 @@ namespace SonicAudioLib.CriMw
|
||||
|
||||
public object[] GetValueArray()
|
||||
{
|
||||
object[] values = new object[header.NumberOfFields];
|
||||
object[] values = new object[header.FieldCount];
|
||||
|
||||
for (int i = 0; i < header.NumberOfFields; i++)
|
||||
for (int i = 0; i < header.FieldCount; i++)
|
||||
{
|
||||
if (fields[i].Flag.HasFlag(CriFieldFlag.Data))
|
||||
{
|
||||
@ -304,6 +303,14 @@ namespace SonicAudioLib.CriMw
|
||||
return values;
|
||||
}
|
||||
|
||||
public IEnumerable GetValues()
|
||||
{
|
||||
for (int i = 0; i < header.FieldCount; i++)
|
||||
{
|
||||
yield return GetValue(i);
|
||||
}
|
||||
}
|
||||
|
||||
public object GetValue(int fieldIndex)
|
||||
{
|
||||
if (fieldIndex < 0 || fieldIndex >= fields.Count)
|
||||
@ -315,7 +322,7 @@ namespace SonicAudioLib.CriMw
|
||||
{
|
||||
if (fields[fieldIndex].Flag.HasFlag(CriFieldFlag.Data))
|
||||
{
|
||||
return new Substream(source, 0, 0);
|
||||
return new SubStream(source, 0, 0);
|
||||
}
|
||||
|
||||
return fields[fieldIndex].Value;
|
||||
@ -450,19 +457,19 @@ namespace SonicAudioLib.CriMw
|
||||
return (string)GetValue(fieldName);
|
||||
}
|
||||
|
||||
public Substream GetSubstream(int fieldIndex)
|
||||
public SubStream GetSubStream(int fieldIndex)
|
||||
{
|
||||
return (Substream)GetValue(fieldIndex);
|
||||
return (SubStream)GetValue(fieldIndex);
|
||||
}
|
||||
|
||||
public Substream GetSubstream(string fieldName)
|
||||
public SubStream GetSubStream(string fieldName)
|
||||
{
|
||||
return (Substream)GetValue(fieldName);
|
||||
return (SubStream)GetValue(fieldName);
|
||||
}
|
||||
|
||||
public byte[] GetData(int fieldIndex)
|
||||
{
|
||||
return GetSubstream(fieldIndex).ToArray();
|
||||
return GetSubStream(fieldIndex).ToArray();
|
||||
}
|
||||
|
||||
public byte[] GetData(string fieldName)
|
||||
@ -470,14 +477,14 @@ namespace SonicAudioLib.CriMw
|
||||
return GetData(GetFieldIndex(fieldName));
|
||||
}
|
||||
|
||||
public CriTableReader GetCriTableReader(string fieldName)
|
||||
public CriTableReader GetTableReader(string fieldName)
|
||||
{
|
||||
return new CriTableReader(GetSubstream(fieldName), false);
|
||||
return new CriTableReader(GetSubStream(fieldName), false);
|
||||
}
|
||||
|
||||
public CriTableReader GetCriTableReader(int fieldIndex)
|
||||
public CriTableReader GetTableReader(int fieldIndex)
|
||||
{
|
||||
return new CriTableReader(GetSubstream(fieldIndex), false);
|
||||
return new CriTableReader(GetSubStream(fieldIndex), false);
|
||||
}
|
||||
|
||||
public uint GetLength(int fieldIndex)
|
||||
@ -493,8 +500,9 @@ namespace SonicAudioLib.CriMw
|
||||
}
|
||||
|
||||
GoToValue(fieldIndex);
|
||||
ReadData(out uint vldPosition, out uint vldLength);
|
||||
return vldLength;
|
||||
|
||||
source.Seek(4, SeekOrigin.Current);
|
||||
return DataStream.ReadUInt32BE(source);
|
||||
}
|
||||
|
||||
public uint GetLength(string fieldName)
|
||||
@ -515,8 +523,7 @@ namespace SonicAudioLib.CriMw
|
||||
}
|
||||
|
||||
GoToValue(fieldIndex);
|
||||
ReadData(out uint vldPosition, out uint vldLength);
|
||||
return headerPosition + header.DataPoolPosition + vldPosition;
|
||||
return (uint)(headerPosition + header.DataPoolPosition + DataStream.ReadUInt32BE(source));
|
||||
}
|
||||
|
||||
public uint GetPosition(string fieldName)
|
||||
@ -544,75 +551,15 @@ namespace SonicAudioLib.CriMw
|
||||
return (Guid)GetValue(fieldName);
|
||||
}
|
||||
|
||||
private byte[] ReadBytes(int length)
|
||||
{
|
||||
return EndianStream.ReadBytes(source, length);
|
||||
}
|
||||
|
||||
private byte ReadByte()
|
||||
{
|
||||
return EndianStream.ReadByte(source);
|
||||
}
|
||||
|
||||
private bool ReadBoolean()
|
||||
{
|
||||
return EndianStream.ReadBoolean(source);
|
||||
}
|
||||
|
||||
private sbyte ReadSByte()
|
||||
{
|
||||
return EndianStream.ReadSByte(source);
|
||||
}
|
||||
|
||||
private ushort ReadUInt16()
|
||||
{
|
||||
return EndianStream.ReadUInt16BE(source);
|
||||
}
|
||||
|
||||
private short ReadInt16()
|
||||
{
|
||||
return EndianStream.ReadInt16BE(source);
|
||||
}
|
||||
|
||||
private uint ReadUInt32()
|
||||
{
|
||||
return EndianStream.ReadUInt32BE(source);
|
||||
}
|
||||
|
||||
private int ReadInt32()
|
||||
{
|
||||
return EndianStream.ReadInt32BE(source);
|
||||
}
|
||||
|
||||
private ulong ReadUInt64()
|
||||
{
|
||||
return EndianStream.ReadUInt64BE(source);
|
||||
}
|
||||
|
||||
private long ReadInt64()
|
||||
{
|
||||
return EndianStream.ReadInt64BE(source);
|
||||
}
|
||||
|
||||
private float ReadSingle()
|
||||
{
|
||||
return EndianStream.ReadSingleBE(source);
|
||||
}
|
||||
|
||||
private double ReadDouble()
|
||||
{
|
||||
return EndianStream.ReadDoubleBE(source);
|
||||
}
|
||||
|
||||
private string ReadString()
|
||||
{
|
||||
uint stringPosition = ReadUInt32();
|
||||
uint stringPosition = DataStream.ReadUInt32BE(source);
|
||||
long previousPosition = source.Position;
|
||||
|
||||
source.Position = headerPosition + header.StringPoolPosition + stringPosition;
|
||||
string readString = EndianStream.ReadCString(source, encoding);
|
||||
|
||||
source.Position = previousPosition;
|
||||
source.Seek(headerPosition + header.StringPoolPosition + stringPosition, SeekOrigin.Begin);
|
||||
string readString = DataStream.ReadCString(source, encoding);
|
||||
|
||||
source.Seek(previousPosition, SeekOrigin.Begin);
|
||||
|
||||
if (readString == StringPool.AdxBlankString || (readString == header.TableName && stringPosition == 0))
|
||||
{
|
||||
@ -622,64 +569,52 @@ namespace SonicAudioLib.CriMw
|
||||
return readString;
|
||||
}
|
||||
|
||||
private void ReadData(out uint vldPosition, out uint vldLength)
|
||||
{
|
||||
vldPosition = ReadUInt32();
|
||||
vldLength = ReadUInt32();
|
||||
}
|
||||
|
||||
private Guid ReadGuid()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
source.Read(buffer, 0, buffer.Length);
|
||||
return new Guid(buffer);
|
||||
}
|
||||
|
||||
private object ReadValue(CriFieldFlag fieldFlag)
|
||||
{
|
||||
switch (fieldFlag & CriFieldFlag.TypeMask)
|
||||
{
|
||||
case CriFieldFlag.Byte:
|
||||
return ReadByte();
|
||||
return DataStream.ReadByte(source);
|
||||
case CriFieldFlag.SByte:
|
||||
return ReadSByte();
|
||||
return DataStream.ReadSByte(source);
|
||||
case CriFieldFlag.UInt16:
|
||||
return ReadUInt16();
|
||||
return DataStream.ReadUInt16BE(source);
|
||||
case CriFieldFlag.Int16:
|
||||
return ReadInt16();
|
||||
return DataStream.ReadInt16BE(source);
|
||||
case CriFieldFlag.UInt32:
|
||||
return ReadUInt32();
|
||||
return DataStream.ReadUInt32BE(source);
|
||||
case CriFieldFlag.Int32:
|
||||
return ReadInt32();
|
||||
return DataStream.ReadInt32BE(source);
|
||||
case CriFieldFlag.UInt64:
|
||||
return ReadUInt64();
|
||||
return DataStream.ReadUInt64BE(source);
|
||||
case CriFieldFlag.Int64:
|
||||
return ReadInt64();
|
||||
return DataStream.ReadInt64BE(source);
|
||||
case CriFieldFlag.Single:
|
||||
return ReadSingle();
|
||||
return DataStream.ReadSingleBE(source);
|
||||
case CriFieldFlag.Double:
|
||||
return ReadDouble();
|
||||
return DataStream.ReadDoubleBE(source);
|
||||
case CriFieldFlag.String:
|
||||
return ReadString();
|
||||
case CriFieldFlag.Data:
|
||||
{
|
||||
ReadData(out uint vldPosition, out uint vldLength);
|
||||
uint position = DataStream.ReadUInt32BE(source);
|
||||
uint length = DataStream.ReadUInt32BE(source);
|
||||
|
||||
// Some ACB files have the length info set to zero for UTF table fields, so find the correct length
|
||||
if (vldPosition > 0 && vldLength == 0)
|
||||
if (position > 0 && length == 0)
|
||||
{
|
||||
source.Position = headerPosition + header.DataPoolPosition + vldPosition;
|
||||
source.Seek(headerPosition + header.DataPoolPosition + position, SeekOrigin.Begin);
|
||||
|
||||
if (EndianStream.ReadCString(source, 4) == CriTableHeader.Signature)
|
||||
if (DataStream.ReadBytes(source, 4).SequenceEqual(CriTableHeader.SignatureBytes))
|
||||
{
|
||||
vldLength = ReadUInt32() + 8;
|
||||
length = DataStream.ReadUInt32BE(source) + 8;
|
||||
}
|
||||
}
|
||||
|
||||
return new Substream(source, headerPosition + header.DataPoolPosition + vldPosition, vldLength);
|
||||
return new SubStream(source, headerPosition + header.DataPoolPosition + position, length);
|
||||
}
|
||||
case CriFieldFlag.Guid:
|
||||
return ReadGuid();
|
||||
return new Guid(DataStream.ReadBytes(source, 16));
|
||||
}
|
||||
|
||||
return null;
|
||||
@ -693,8 +628,6 @@ namespace SonicAudioLib.CriMw
|
||||
{
|
||||
source.Close();
|
||||
}
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
public static CriTableReader Create(byte[] sourceByteArray)
|
||||
|
@ -4,8 +4,9 @@ using System.Text;
|
||||
using System.ComponentModel;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using System.Linq;
|
||||
using SonicAudioLib.IO;
|
||||
using SonicAudioLib.Module;
|
||||
using SonicAudioLib.FileBases;
|
||||
|
||||
namespace SonicAudioLib.CriMw
|
||||
{
|
||||
@ -25,7 +26,7 @@ namespace SonicAudioLib.CriMw
|
||||
private List<CriTableField> fields;
|
||||
private Stream destination;
|
||||
private CriTableHeader header;
|
||||
private VldPool vldPool;
|
||||
private DataPool vldPool;
|
||||
private StringPool stringPool;
|
||||
private uint headerPosition;
|
||||
|
||||
@ -62,24 +63,16 @@ namespace SonicAudioLib.CriMw
|
||||
status = Status.Start;
|
||||
|
||||
headerPosition = (uint)destination.Position;
|
||||
header.TableName = tableName;
|
||||
|
||||
if (settings.PutBlankString)
|
||||
{
|
||||
stringPool.Put(StringPool.AdxBlankString);
|
||||
}
|
||||
|
||||
EndianStream.WriteCString(destination, CriTableHeader.Signature, 4);
|
||||
WriteUInt32(uint.MinValue);
|
||||
WriteByte(byte.MinValue);
|
||||
WriteByte(byte.MinValue);
|
||||
WriteUInt16(ushort.MinValue);
|
||||
WriteUInt32(uint.MinValue);
|
||||
WriteUInt32(uint.MinValue);
|
||||
WriteString(tableName);
|
||||
WriteUInt16(ushort.MinValue);
|
||||
WriteUInt16(ushort.MinValue);
|
||||
WriteUInt32(uint.MinValue);
|
||||
header.TableNamePosition = (uint)stringPool.Put(tableName);
|
||||
|
||||
var buffer = new byte[32];
|
||||
destination.Write(buffer, 0, 32);
|
||||
}
|
||||
|
||||
public void WriteEndTable()
|
||||
@ -96,17 +89,17 @@ namespace SonicAudioLib.CriMw
|
||||
|
||||
status = Status.End;
|
||||
|
||||
destination.Seek(headerPosition + header.RowsPosition + (header.RowLength * header.NumberOfRows), SeekOrigin.Begin);
|
||||
destination.Seek(headerPosition + header.RowsPosition + (header.RowLength * header.RowCount), SeekOrigin.Begin);
|
||||
|
||||
stringPool.Write(destination);
|
||||
header.StringPoolPosition = (uint)stringPool.Position - headerPosition;
|
||||
|
||||
EndianStream.Pad(destination, vldPool.Align);
|
||||
DataStream.Pad(destination, vldPool.Align);
|
||||
|
||||
vldPool.Write(destination);
|
||||
header.DataPoolPosition = (uint)vldPool.Position - headerPosition;
|
||||
|
||||
EndianStream.Pad(destination, vldPool.Align);
|
||||
DataStream.Pad(destination, vldPool.Align);
|
||||
|
||||
long previousPosition = destination.Position;
|
||||
|
||||
@ -122,21 +115,23 @@ namespace SonicAudioLib.CriMw
|
||||
header.EncodingType = CriTableHeader.EncodingTypeUtf8;
|
||||
}
|
||||
|
||||
destination.Position = headerPosition + 4;
|
||||
WriteUInt32(header.Length - 8);
|
||||
WriteByte(header.UnknownByte);
|
||||
WriteByte(header.EncodingType);
|
||||
WriteUInt16((ushort)(header.RowsPosition - 8));
|
||||
WriteUInt32(header.StringPoolPosition - 8);
|
||||
WriteUInt32(header.DataPoolPosition - 8);
|
||||
destination.Seek(4, SeekOrigin.Current);
|
||||
WriteUInt16(header.NumberOfFields);
|
||||
WriteUInt16(header.RowLength);
|
||||
WriteUInt32(header.NumberOfRows);
|
||||
destination.Seek(headerPosition, SeekOrigin.Begin);
|
||||
|
||||
destination.Write(CriTableHeader.SignatureBytes, 0, 4);
|
||||
DataStream.WriteUInt32BE(destination, header.Length - 8);
|
||||
DataStream.WriteByte(destination, header.UnknownByte);
|
||||
DataStream.WriteByte(destination, header.EncodingType);
|
||||
DataStream.WriteUInt16BE(destination, (ushort)(header.RowsPosition - 8));
|
||||
DataStream.WriteUInt32BE(destination, header.StringPoolPosition - 8);
|
||||
DataStream.WriteUInt32BE(destination, header.DataPoolPosition - 8);
|
||||
DataStream.WriteUInt32BE(destination, header.TableNamePosition);
|
||||
DataStream.WriteUInt16BE(destination, header.FieldCount);
|
||||
DataStream.WriteUInt16BE(destination, header.RowLength);
|
||||
DataStream.WriteUInt32BE(destination, header.RowCount);
|
||||
|
||||
if (settings.EnableMask)
|
||||
{
|
||||
destination.Position = headerPosition;
|
||||
destination.Seek(headerPosition, SeekOrigin.Begin);
|
||||
CriTableMasker.Mask(destination, header.Length, settings.MaskXor, settings.MaskXorMultiplier);
|
||||
}
|
||||
|
||||
@ -179,7 +174,7 @@ namespace SonicAudioLib.CriMw
|
||||
Value = defaultValue
|
||||
};
|
||||
|
||||
WriteByte((byte)field.Flag);
|
||||
DataStream.WriteByte(destination, (byte)field.Flag);
|
||||
|
||||
if (!string.IsNullOrEmpty(fieldName))
|
||||
{
|
||||
@ -192,7 +187,7 @@ namespace SonicAudioLib.CriMw
|
||||
}
|
||||
|
||||
fields.Add(field);
|
||||
header.NumberOfFields++;
|
||||
header.FieldCount++;
|
||||
}
|
||||
|
||||
public void WriteField(string fieldName, Type fieldType)
|
||||
@ -215,15 +210,40 @@ namespace SonicAudioLib.CriMw
|
||||
Name = fieldName
|
||||
};
|
||||
|
||||
WriteByte((byte)field.Flag);
|
||||
DataStream.WriteByte(destination, (byte)field.Flag);
|
||||
|
||||
if (!string.IsNullOrEmpty(fieldName))
|
||||
{
|
||||
WriteString(field.Name);
|
||||
}
|
||||
|
||||
field.Offset = header.RowLength;
|
||||
switch (field.Flag & CriFieldFlag.TypeMask)
|
||||
{
|
||||
case CriFieldFlag.Byte:
|
||||
case CriFieldFlag.SByte:
|
||||
header.RowLength += 1;
|
||||
break;
|
||||
case CriFieldFlag.Int16:
|
||||
case CriFieldFlag.UInt16:
|
||||
header.RowLength += 2;
|
||||
break;
|
||||
case CriFieldFlag.Int32:
|
||||
case CriFieldFlag.UInt32:
|
||||
case CriFieldFlag.Single:
|
||||
case CriFieldFlag.String:
|
||||
header.RowLength += 4;
|
||||
break;
|
||||
case CriFieldFlag.Int64:
|
||||
case CriFieldFlag.UInt64:
|
||||
case CriFieldFlag.Double:
|
||||
case CriFieldFlag.Data:
|
||||
header.RowLength += 8;
|
||||
break;
|
||||
}
|
||||
|
||||
fields.Add(field);
|
||||
header.NumberOfFields++;
|
||||
header.FieldCount++;
|
||||
}
|
||||
|
||||
public void WriteField(CriField criField)
|
||||
@ -241,7 +261,6 @@ namespace SonicAudioLib.CriMw
|
||||
status = Status.Idle;
|
||||
|
||||
header.RowsPosition = (ushort)(destination.Position - headerPosition);
|
||||
header.RowLength = CalculateRowLength();
|
||||
}
|
||||
|
||||
public void WriteStartRow()
|
||||
@ -258,9 +277,9 @@ namespace SonicAudioLib.CriMw
|
||||
|
||||
status = Status.Row;
|
||||
|
||||
header.NumberOfRows++;
|
||||
header.RowCount++;
|
||||
|
||||
destination.Position = headerPosition + header.RowsPosition + (header.NumberOfRows * header.RowLength);
|
||||
destination.Seek(headerPosition + header.RowsPosition + (header.RowCount * header.RowLength), SeekOrigin.Begin);
|
||||
byte[] buffer = new byte[header.RowLength];
|
||||
destination.Write(buffer, 0, buffer.Length);
|
||||
}
|
||||
@ -283,80 +302,7 @@ namespace SonicAudioLib.CriMw
|
||||
|
||||
private void GoToValue(int fieldIndex)
|
||||
{
|
||||
long position = headerPosition + header.RowsPosition + (header.RowLength * (header.NumberOfRows - 1));
|
||||
|
||||
for (int i = 0; i < fieldIndex; i++)
|
||||
{
|
||||
if (!fields[i].Flag.HasFlag(CriFieldFlag.RowStorage))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (fields[i].Flag & CriFieldFlag.TypeMask)
|
||||
{
|
||||
case CriFieldFlag.Byte:
|
||||
case CriFieldFlag.SByte:
|
||||
position += 1;
|
||||
break;
|
||||
case CriFieldFlag.Int16:
|
||||
case CriFieldFlag.UInt16:
|
||||
position += 2;
|
||||
break;
|
||||
case CriFieldFlag.Int32:
|
||||
case CriFieldFlag.UInt32:
|
||||
case CriFieldFlag.Single:
|
||||
case CriFieldFlag.String:
|
||||
position += 4;
|
||||
break;
|
||||
case CriFieldFlag.Int64:
|
||||
case CriFieldFlag.UInt64:
|
||||
case CriFieldFlag.Double:
|
||||
case CriFieldFlag.Data:
|
||||
position += 8;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
destination.Position = position;
|
||||
}
|
||||
|
||||
private ushort CalculateRowLength()
|
||||
{
|
||||
ushort length = 0;
|
||||
|
||||
for (int i = 0; i < fields.Count; i++)
|
||||
{
|
||||
if (!fields[i].Flag.HasFlag(CriFieldFlag.RowStorage))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (fields[i].Flag & CriFieldFlag.TypeMask)
|
||||
{
|
||||
case CriFieldFlag.Byte:
|
||||
case CriFieldFlag.SByte:
|
||||
length += 1;
|
||||
break;
|
||||
case CriFieldFlag.Int16:
|
||||
case CriFieldFlag.UInt16:
|
||||
length += 2;
|
||||
break;
|
||||
case CriFieldFlag.Int32:
|
||||
case CriFieldFlag.UInt32:
|
||||
case CriFieldFlag.Single:
|
||||
case CriFieldFlag.String:
|
||||
length += 4;
|
||||
break;
|
||||
case CriFieldFlag.Int64:
|
||||
case CriFieldFlag.UInt64:
|
||||
case CriFieldFlag.Double:
|
||||
case CriFieldFlag.Data:
|
||||
length += 8;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return length;
|
||||
destination.Seek(headerPosition + header.RowsPosition + (header.RowLength * (header.RowCount - 1)) + fields[fieldIndex].Offset, SeekOrigin.Begin);
|
||||
}
|
||||
|
||||
public void WriteEndRow()
|
||||
@ -384,146 +330,61 @@ namespace SonicAudioLib.CriMw
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteByte(byte value)
|
||||
{
|
||||
EndianStream.WriteByte(destination, value);
|
||||
}
|
||||
|
||||
private void WriteBoolean(bool value)
|
||||
{
|
||||
EndianStream.WriteBoolean(destination, value);
|
||||
}
|
||||
|
||||
private void WriteSByte(sbyte value)
|
||||
{
|
||||
EndianStream.WriteSByte(destination, value);
|
||||
}
|
||||
|
||||
private void WriteUInt16(ushort value)
|
||||
{
|
||||
EndianStream.WriteUInt16BE(destination, value);
|
||||
}
|
||||
|
||||
private void WriteInt16(short value)
|
||||
{
|
||||
EndianStream.WriteInt16BE(destination, value);
|
||||
}
|
||||
|
||||
private void WriteUInt32(uint value)
|
||||
{
|
||||
EndianStream.WriteUInt32BE(destination, value);
|
||||
}
|
||||
|
||||
private void WriteInt32(int value)
|
||||
{
|
||||
EndianStream.WriteInt32BE(destination, value);
|
||||
}
|
||||
|
||||
private void WriteUInt64(ulong value)
|
||||
{
|
||||
EndianStream.WriteUInt64BE(destination, value);
|
||||
}
|
||||
|
||||
private void WriteInt64(long value)
|
||||
{
|
||||
EndianStream.WriteInt64BE(destination, value);
|
||||
}
|
||||
|
||||
private void WriteSingle(float value)
|
||||
{
|
||||
EndianStream.WriteSingleBE(destination, value);
|
||||
}
|
||||
|
||||
private void WriteDouble(double value)
|
||||
{
|
||||
EndianStream.WriteDoubleBE(destination, value);
|
||||
}
|
||||
|
||||
private void WriteString(string value)
|
||||
{
|
||||
if (settings.RemoveDuplicateStrings && stringPool.ContainsString(value))
|
||||
{
|
||||
WriteUInt32((uint)stringPool.GetStringPosition(value));
|
||||
DataStream.WriteUInt32BE(destination, (uint)stringPool.GetStringPosition(value));
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
WriteUInt32((uint)stringPool.Put(value));
|
||||
DataStream.WriteUInt32BE(destination, (uint)stringPool.Put(value));
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteData(byte[] data)
|
||||
{
|
||||
WriteUInt32((uint)vldPool.Put(data));
|
||||
WriteUInt32((uint)data.Length);
|
||||
}
|
||||
|
||||
private void WriteStream(Stream stream)
|
||||
{
|
||||
WriteUInt32((uint)vldPool.Put(stream));
|
||||
WriteUInt32((uint)stream.Length);
|
||||
}
|
||||
|
||||
private void WriteFile(FileInfo fileInfo)
|
||||
{
|
||||
WriteUInt32((uint)vldPool.Put(fileInfo));
|
||||
WriteUInt32((uint)fileInfo.Length);
|
||||
}
|
||||
|
||||
private void WriteModule(ModuleBase module)
|
||||
{
|
||||
WriteUInt32((uint)vldPool.Put(module));
|
||||
WriteUInt32(0);
|
||||
}
|
||||
|
||||
private void WriteGuid(Guid guid)
|
||||
{
|
||||
byte[] buffer = guid.ToByteArray();
|
||||
destination.Write(buffer, 0, buffer.Length);
|
||||
}
|
||||
|
||||
private void WriteValue(object val)
|
||||
{
|
||||
switch (val)
|
||||
{
|
||||
case byte value:
|
||||
WriteByte(value);
|
||||
DataStream.WriteByte(destination, value);
|
||||
break;
|
||||
|
||||
case sbyte value:
|
||||
WriteSByte(value);
|
||||
DataStream.WriteSByte(destination, value);
|
||||
break;
|
||||
|
||||
case ushort value:
|
||||
WriteUInt16(value);
|
||||
DataStream.WriteUInt16BE(destination, value);
|
||||
break;
|
||||
|
||||
case short value:
|
||||
WriteInt16(value);
|
||||
DataStream.WriteInt16BE(destination, value);
|
||||
break;
|
||||
|
||||
case uint value:
|
||||
WriteUInt32(value);
|
||||
DataStream.WriteUInt32BE(destination, value);
|
||||
break;
|
||||
|
||||
case int value:
|
||||
WriteInt32(value);
|
||||
DataStream.WriteInt32BE(destination, value);
|
||||
break;
|
||||
|
||||
case ulong value:
|
||||
WriteUInt64(value);
|
||||
DataStream.WriteUInt64BE(destination, value);
|
||||
break;
|
||||
|
||||
case long value:
|
||||
WriteInt64(value);
|
||||
DataStream.WriteInt64BE(destination, value);
|
||||
break;
|
||||
|
||||
case float value:
|
||||
WriteSingle(value);
|
||||
DataStream.WriteSingleBE(destination, value);
|
||||
break;
|
||||
|
||||
case double value:
|
||||
WriteDouble(value);
|
||||
DataStream.WriteDoubleBE(destination, value);
|
||||
break;
|
||||
|
||||
case string value:
|
||||
@ -531,23 +392,22 @@ namespace SonicAudioLib.CriMw
|
||||
break;
|
||||
|
||||
case byte[] value:
|
||||
WriteData(value);
|
||||
DataStream.WriteUInt32BE(destination, (uint)vldPool.Put(value));
|
||||
DataStream.WriteUInt32BE(destination, (uint)value.Length);
|
||||
break;
|
||||
|
||||
case Guid value:
|
||||
WriteGuid(value);
|
||||
destination.Write(value.ToByteArray(), 0, 16);
|
||||
break;
|
||||
|
||||
case Stream stream:
|
||||
WriteStream(stream);
|
||||
case Stream value:
|
||||
DataStream.WriteUInt32BE(destination, (uint)vldPool.Put(value));
|
||||
DataStream.WriteUInt32BE(destination, (uint)value.Length);
|
||||
break;
|
||||
|
||||
case ModuleBase module:
|
||||
WriteModule(module);
|
||||
break;
|
||||
|
||||
case FileInfo fileInfo:
|
||||
WriteFile(fileInfo);
|
||||
case FileInfo value:
|
||||
DataStream.WriteUInt32BE(destination, (uint)vldPool.Put(value));
|
||||
DataStream.WriteUInt32BE(destination, (uint)value.Length);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -598,7 +458,7 @@ namespace SonicAudioLib.CriMw
|
||||
header = new CriTableHeader();
|
||||
fields = new List<CriTableField>();
|
||||
stringPool = new StringPool(settings.EncodingType);
|
||||
vldPool = new VldPool(settings.Align);
|
||||
vldPool = new DataPool(settings.Align);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -160,7 +160,7 @@ namespace SonicAudioLib.CriMw.Serialization
|
||||
}
|
||||
}
|
||||
|
||||
else if (arrayList == null || (arrayList != null && arrayList.Count == 0))
|
||||
else if (arrayList == null || (arrayList != null && (arrayList.Count == 0 || (arrayList.Count == 1 && propertyInfo.GetValue(arrayList[0]) is null))))
|
||||
{
|
||||
useDefaultValue = true;
|
||||
defaultValue = null;
|
||||
@ -168,7 +168,7 @@ namespace SonicAudioLib.CriMw.Serialization
|
||||
|
||||
if (defaultValue is bool boolean)
|
||||
{
|
||||
defaultValue = boolean ? (byte)1 : (byte)0;
|
||||
defaultValue = (byte)(boolean ? 1 : 0);
|
||||
}
|
||||
|
||||
else if (defaultValue is Enum)
|
||||
@ -204,7 +204,7 @@ namespace SonicAudioLib.CriMw.Serialization
|
||||
|
||||
if (value is bool boolean)
|
||||
{
|
||||
value = boolean ? (byte)1 : (byte)0;
|
||||
value = (byte)(boolean ? 1 : 0);
|
||||
}
|
||||
|
||||
else if (value is Enum)
|
||||
@ -309,7 +309,7 @@ namespace SonicAudioLib.CriMw.Serialization
|
||||
|
||||
object value = tableReader.GetValue(fieldName);
|
||||
|
||||
if (value is Substream substream)
|
||||
if (value is SubStream substream)
|
||||
{
|
||||
value = substream.ToArray();
|
||||
}
|
||||
|
@ -4,9 +4,9 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
|
||||
namespace SonicAudioLib.Module
|
||||
namespace SonicAudioLib.FileBases
|
||||
{
|
||||
public abstract class ModuleBase
|
||||
public abstract class FileBase
|
||||
{
|
||||
protected int bufferSize = 4096;
|
||||
|
38
Source/SonicAudioLib/FileBases/FileXmlBase.cs
Normal file
38
Source/SonicAudioLib/FileBases/FileXmlBase.cs
Normal file
@ -0,0 +1,38 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using System.Xml;
|
||||
|
||||
namespace SonicAudioLib.FileBases
|
||||
{
|
||||
// Because C# doesn't allow you to inherit
|
||||
// more than 1 abstract class.
|
||||
public abstract class FileXmlBase : FileBase
|
||||
{
|
||||
public abstract void ReadXml(XmlReader reader);
|
||||
public abstract void WriteXml(XmlWriter writer);
|
||||
|
||||
public virtual void LoadXml(string sourceFileName)
|
||||
{
|
||||
using (XmlReader reader = XmlReader.Create(sourceFileName))
|
||||
{
|
||||
ReadXml(reader);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void SaveXml(string destinationFileName)
|
||||
{
|
||||
var settings = new XmlWriterSettings();
|
||||
settings.Indent = true;
|
||||
|
||||
using (XmlWriter writer = XmlWriter.Create(destinationFileName, settings))
|
||||
{
|
||||
WriteXml(writer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -5,7 +5,7 @@ using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.IO;
|
||||
|
||||
using SonicAudioLib.Archive;
|
||||
using SonicAudioLib.Archives;
|
||||
|
||||
namespace SonicAudioLib.IO
|
||||
{
|
||||
@ -23,7 +23,6 @@ namespace SonicAudioLib.IO
|
||||
public string DestinationFileName { get; set; }
|
||||
public long Position { get; set; }
|
||||
public long Length { get; set; }
|
||||
public bool DecompressFromCriLayla { get; set; }
|
||||
}
|
||||
|
||||
private List<Item> items = new List<Item>();
|
||||
@ -34,9 +33,9 @@ namespace SonicAudioLib.IO
|
||||
|
||||
public event ProgressChanged ProgressChanged;
|
||||
|
||||
public void Add(object source, string destinationFileName, long position, long length, bool decompressFromCriLayla = false)
|
||||
public void Add(object source, string destinationFileName, long position, long length)
|
||||
{
|
||||
items.Add(new Item { Source = source, DestinationFileName = destinationFileName, Position = position, Length = length, DecompressFromCriLayla = decompressFromCriLayla });
|
||||
items.Add(new Item { Source = source, DestinationFileName = destinationFileName, Position = position, Length = length, });
|
||||
}
|
||||
|
||||
public void Run()
|
||||
@ -64,23 +63,15 @@ namespace SonicAudioLib.IO
|
||||
destinationFileName.Directory.Create();
|
||||
}
|
||||
|
||||
using (Stream source =
|
||||
using (Stream source =
|
||||
item.Source is string fileName ? new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read, BufferSize) :
|
||||
item.Source is byte[] byteArray ? new MemoryStream(byteArray) :
|
||||
item.Source is byte[] byteArray ? new MemoryStream(byteArray) :
|
||||
item.Source is Stream stream ? stream :
|
||||
throw new ArgumentException("Unknown source in item", nameof(item.Source))
|
||||
)
|
||||
using (Stream destination = destinationFileName.Create())
|
||||
{
|
||||
if (item.DecompressFromCriLayla)
|
||||
{
|
||||
CriCpkArchive.Decompress(source, item.Position, destination);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
EndianStream.CopyPartTo(source, destination, item.Position, item.Length, BufferSize);
|
||||
}
|
||||
DataStream.CopyPartTo(source, destination, item.Position, item.Length, BufferSize);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
|
||||
using SonicAudioLib.Module;
|
||||
using SonicAudioLib.FileBases;
|
||||
|
||||
namespace SonicAudioLib.IO
|
||||
{
|
||||
public class VldPool
|
||||
public class DataPool
|
||||
{
|
||||
private ArrayList items = new ArrayList();
|
||||
|
||||
@ -88,29 +88,13 @@ namespace SonicAudioLib.IO
|
||||
return position;
|
||||
}
|
||||
|
||||
public long Put(ModuleBase module)
|
||||
{
|
||||
if (module == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
length = Helpers.Align(length, align);
|
||||
|
||||
long position = length;
|
||||
length += 0;
|
||||
items.Add(module);
|
||||
|
||||
return position;
|
||||
}
|
||||
|
||||
public void Write(Stream destination)
|
||||
{
|
||||
startPosition = destination.Position;
|
||||
|
||||
foreach (object item in items)
|
||||
{
|
||||
EndianStream.Pad(destination, align);
|
||||
DataStream.Pad(destination, align);
|
||||
|
||||
if (item is byte[] bytes)
|
||||
{
|
||||
@ -131,11 +115,6 @@ namespace SonicAudioLib.IO
|
||||
}
|
||||
}
|
||||
|
||||
else if (item is ModuleBase module)
|
||||
{
|
||||
module.Write(destination);
|
||||
}
|
||||
|
||||
ProgressChanged?.Invoke(this, new ProgressChangedEventArgs(((destination.Position - startPosition) / (double)(length - baseLength)) * 100.0));
|
||||
}
|
||||
}
|
||||
@ -145,7 +124,7 @@ namespace SonicAudioLib.IO
|
||||
items.Clear();
|
||||
}
|
||||
|
||||
public VldPool(uint align, long baseLength)
|
||||
public DataPool(uint align, long baseLength)
|
||||
{
|
||||
this.align = align;
|
||||
|
||||
@ -153,12 +132,12 @@ namespace SonicAudioLib.IO
|
||||
length = this.baseLength;
|
||||
}
|
||||
|
||||
public VldPool(uint align)
|
||||
public DataPool(uint align)
|
||||
{
|
||||
this.align = align;
|
||||
}
|
||||
|
||||
public VldPool()
|
||||
public DataPool()
|
||||
{
|
||||
}
|
||||
}
|
@ -6,7 +6,7 @@ using System.Runtime.InteropServices;
|
||||
|
||||
namespace SonicAudioLib.IO
|
||||
{
|
||||
public static class EndianStream
|
||||
public static class DataStream
|
||||
{
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
private struct SingleUnion
|
||||
@ -28,6 +28,9 @@ namespace SonicAudioLib.IO
|
||||
public ulong ULong;
|
||||
}
|
||||
|
||||
// Not thread safe... but I guess it's OK.
|
||||
private static byte[] buffer = new byte[8];
|
||||
|
||||
public static void CopyTo(Stream source, Stream destination)
|
||||
{
|
||||
CopyTo(source, destination, 4096);
|
||||
@ -44,43 +47,44 @@ namespace SonicAudioLib.IO
|
||||
}
|
||||
}
|
||||
|
||||
public static void CopyPartTo(Stream source, Stream destination, long position, long length, int bufferSize)
|
||||
public static void CopyPartTo(Stream source, Stream destination, long length, int bufferSize)
|
||||
{
|
||||
source.Position = position;
|
||||
|
||||
int num;
|
||||
byte[] buffer = new byte[bufferSize];
|
||||
|
||||
int num;
|
||||
long totalWrittenBytes = 0;
|
||||
|
||||
while ((num = source.Read(buffer, 0, bufferSize)) != 0)
|
||||
long copiedBytes = 0;
|
||||
while (copiedBytes < length && (num = source.Read(buffer, 0, bufferSize)) != 0)
|
||||
{
|
||||
totalWrittenBytes += num;
|
||||
|
||||
if (totalWrittenBytes > length)
|
||||
if (copiedBytes + num >= length)
|
||||
{
|
||||
num -= (int)(totalWrittenBytes - length);
|
||||
destination.Write(buffer, 0, num);
|
||||
break;
|
||||
num = (int)(length - copiedBytes);
|
||||
}
|
||||
|
||||
copiedBytes += num;
|
||||
destination.Write(buffer, 0, num);
|
||||
}
|
||||
}
|
||||
|
||||
public static void CopyPartTo(Stream source, Stream destination, long position, long length, int bufferSize)
|
||||
{
|
||||
source.Seek(position, SeekOrigin.Begin);
|
||||
CopyPartTo(source, destination, length, bufferSize);
|
||||
}
|
||||
|
||||
public static byte[] ReadBytes(Stream source, int length)
|
||||
{
|
||||
byte[] buffer = new byte[length];
|
||||
source.Read(buffer, 0, length);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public static byte[] ReadBytesAt(Stream source, int length, long position)
|
||||
{
|
||||
long oldPosition = source.Position;
|
||||
source.Position = position;
|
||||
source.Seek(position, SeekOrigin.Begin);
|
||||
var result = ReadBytes(source, length);
|
||||
source.Position = oldPosition;
|
||||
source.Seek(oldPosition, SeekOrigin.Begin);
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -97,234 +101,288 @@ namespace SonicAudioLib.IO
|
||||
|
||||
public static byte ReadByte(Stream source)
|
||||
{
|
||||
int value = source.ReadByte();
|
||||
if (value == -1)
|
||||
{
|
||||
throw new EndOfStreamException();
|
||||
}
|
||||
source.Read(buffer, 0, 1);
|
||||
|
||||
return (byte)value;
|
||||
return buffer[0];
|
||||
}
|
||||
|
||||
public static byte ReadByteAt(Stream source, long position)
|
||||
{
|
||||
long oldPosition = source.Position;
|
||||
source.Position = position;
|
||||
source.Seek(position, SeekOrigin.Begin);
|
||||
|
||||
byte value = ReadByte(source);
|
||||
source.Position = oldPosition;
|
||||
source.Seek(oldPosition, SeekOrigin.Begin);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static void WriteByte(Stream destination, byte value)
|
||||
{
|
||||
destination.WriteByte(value);
|
||||
buffer[0] = value;
|
||||
|
||||
destination.Write(buffer, 0, 1);
|
||||
}
|
||||
|
||||
public static void WriteByteAt(Stream destination, byte value, long position)
|
||||
{
|
||||
long oldPosition = destination.Position;
|
||||
destination.Position = position;
|
||||
destination.Seek(position, SeekOrigin.Begin);
|
||||
|
||||
WriteByte(destination, value);
|
||||
destination.Position = oldPosition;
|
||||
destination.Seek(oldPosition, SeekOrigin.Begin);
|
||||
}
|
||||
|
||||
public static bool ReadBoolean(Stream source)
|
||||
{
|
||||
return source.ReadByte() > 0;
|
||||
source.Read(buffer, 0, 1);
|
||||
|
||||
return buffer[0] == 1;
|
||||
}
|
||||
|
||||
public static void WriteBoolean(Stream destination, bool value)
|
||||
{
|
||||
WriteByte(destination, (byte)(value ? 1 : 0));
|
||||
buffer[0] = (byte)(value ? 1 : 0);
|
||||
|
||||
destination.Write(buffer, 0, 1);
|
||||
}
|
||||
|
||||
public static sbyte ReadSByte(Stream source)
|
||||
{
|
||||
return (sbyte)ReadByte(source);
|
||||
source.Read(buffer, 0, 1);
|
||||
|
||||
return (sbyte)buffer[0];
|
||||
}
|
||||
|
||||
public static void WriteSByte(Stream source, sbyte value)
|
||||
public static void WriteSByte(Stream destination, sbyte value)
|
||||
{
|
||||
WriteByte(source, (byte)value);
|
||||
buffer[0] = (byte)value;
|
||||
|
||||
destination.Write(buffer, 0, 1);
|
||||
}
|
||||
|
||||
public static ushort ReadUInt16(Stream source)
|
||||
{
|
||||
return (ushort)(source.ReadByte() | source.ReadByte() << 8);
|
||||
source.Read(buffer, 0, 2);
|
||||
|
||||
return (ushort)(buffer[0] | buffer[1] << 8);
|
||||
}
|
||||
|
||||
public static ushort ReadUInt16BE(Stream source)
|
||||
{
|
||||
return (ushort)(source.ReadByte() << 8 | source.ReadByte());
|
||||
source.Read(buffer, 0, 2);
|
||||
|
||||
return (ushort)(buffer[0] << 8 | buffer[1]);
|
||||
}
|
||||
|
||||
public static void WriteUInt16(Stream destination, ushort value)
|
||||
{
|
||||
destination.WriteByte((byte)(value));
|
||||
destination.WriteByte((byte)(value >> 8));
|
||||
buffer[0] = (byte)(value);
|
||||
buffer[1] = (byte)(value >> 8);
|
||||
|
||||
destination.Write(buffer, 0, 2);
|
||||
}
|
||||
|
||||
public static void WriteUInt16BE(Stream destination, ushort value)
|
||||
{
|
||||
destination.WriteByte((byte)(value >> 8));
|
||||
destination.WriteByte((byte)(value));
|
||||
buffer[0] = (byte)(value >> 8);
|
||||
buffer[1] = (byte)(value);
|
||||
|
||||
destination.Write(buffer, 0, 2);
|
||||
}
|
||||
|
||||
public static short ReadInt16(Stream source)
|
||||
{
|
||||
return (short)(source.ReadByte() | source.ReadByte() << 8);
|
||||
source.Read(buffer, 0, 2);
|
||||
|
||||
return (short)(buffer[0] | buffer[1] << 8);
|
||||
}
|
||||
|
||||
public static short ReadInt16BE(Stream source)
|
||||
{
|
||||
return (short)(source.ReadByte() << 8 | source.ReadByte());
|
||||
source.Read(buffer, 0, 2);
|
||||
|
||||
return (short)(buffer[0] << 8 | buffer[1]);
|
||||
}
|
||||
|
||||
public static void WriteInt16(Stream destination, short value)
|
||||
{
|
||||
destination.WriteByte((byte)(value));
|
||||
destination.WriteByte((byte)(value >> 8));
|
||||
buffer[0] = (byte)(value);
|
||||
buffer[1] = (byte)(value >> 8);
|
||||
|
||||
destination.Write(buffer, 0, 2);
|
||||
}
|
||||
|
||||
public static void WriteInt16BE(Stream destination, short value)
|
||||
{
|
||||
destination.WriteByte((byte)(value >> 8));
|
||||
destination.WriteByte((byte)(value));
|
||||
buffer[0] = (byte)(value >> 8);
|
||||
buffer[1] = (byte)(value);
|
||||
|
||||
destination.Write(buffer, 0, 2);
|
||||
}
|
||||
|
||||
public static uint ReadUInt32(Stream source)
|
||||
{
|
||||
return (uint)(source.ReadByte() | source.ReadByte() << 8 | source.ReadByte() << 16 | source.ReadByte() << 24);
|
||||
source.Read(buffer, 0, 4);
|
||||
|
||||
return (uint)(buffer[0] | buffer[1] << 8 | buffer[2] << 16 | buffer[3] << 24);
|
||||
}
|
||||
|
||||
public static uint ReadUInt32BE(Stream source)
|
||||
{
|
||||
return (uint)(source.ReadByte() << 24 | source.ReadByte() << 16 | source.ReadByte() << 8 | source.ReadByte());
|
||||
source.Read(buffer, 0, 4);
|
||||
|
||||
return (uint)(buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3]);
|
||||
}
|
||||
|
||||
public static void WriteUInt32(Stream destination, uint value)
|
||||
{
|
||||
destination.WriteByte((byte)(value));
|
||||
destination.WriteByte((byte)(value >> 8));
|
||||
destination.WriteByte((byte)(value >> 16));
|
||||
destination.WriteByte((byte)(value >> 24));
|
||||
buffer[0] = (byte)(value);
|
||||
buffer[1] = (byte)(value >> 8);
|
||||
buffer[2] = (byte)(value >> 16);
|
||||
buffer[3] = (byte)(value >> 24);
|
||||
|
||||
destination.Write(buffer, 0, 4);
|
||||
}
|
||||
|
||||
public static void WriteUInt32BE(Stream destination, uint value)
|
||||
{
|
||||
destination.WriteByte((byte)((value >> 24)));
|
||||
destination.WriteByte((byte)((value >> 16)));
|
||||
destination.WriteByte((byte)((value >> 8)));
|
||||
destination.WriteByte((byte)(value));
|
||||
buffer[0] = (byte)((value >> 24));
|
||||
buffer[1] = (byte)((value >> 16));
|
||||
buffer[2] = (byte)((value >> 8));
|
||||
buffer[3] = (byte)(value);
|
||||
|
||||
destination.Write(buffer, 0, 4);
|
||||
}
|
||||
|
||||
public static int ReadInt32(Stream source)
|
||||
{
|
||||
return source.ReadByte() | source.ReadByte() << 8 | source.ReadByte() << 16 | source.ReadByte() << 24;
|
||||
source.Read(buffer, 0, 4);
|
||||
|
||||
return buffer[0] | buffer[1] << 8 | buffer[2] << 16 | buffer[3] << 24;
|
||||
}
|
||||
|
||||
public static int ReadInt32BE(Stream source)
|
||||
{
|
||||
return source.ReadByte() << 24 | source.ReadByte() << 16 | source.ReadByte() << 8 | source.ReadByte();
|
||||
source.Read(buffer, 0, 4);
|
||||
|
||||
return buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3];
|
||||
}
|
||||
|
||||
public static void WriteInt32(Stream destination, int value)
|
||||
{
|
||||
destination.WriteByte((byte)(value));
|
||||
destination.WriteByte((byte)(value >> 8));
|
||||
destination.WriteByte((byte)(value >> 16));
|
||||
destination.WriteByte((byte)(value >> 24));
|
||||
buffer[0] = (byte)(value);
|
||||
buffer[1] = (byte)(value >> 8);
|
||||
buffer[2] = (byte)(value >> 16);
|
||||
buffer[3] = (byte)(value >> 24);
|
||||
|
||||
destination.Write(buffer, 0, 4);
|
||||
}
|
||||
|
||||
public static void WriteInt32BE(Stream destination, int value)
|
||||
{
|
||||
destination.WriteByte((byte)((value >> 24)));
|
||||
destination.WriteByte((byte)((value >> 16)));
|
||||
destination.WriteByte((byte)((value >> 8)));
|
||||
destination.WriteByte((byte)(value));
|
||||
buffer[0] = (byte)((value >> 24));
|
||||
buffer[1] = (byte)((value >> 16));
|
||||
buffer[2] = (byte)((value >> 8));
|
||||
buffer[3] = (byte)(value);
|
||||
|
||||
destination.Write(buffer, 0, 4);
|
||||
}
|
||||
|
||||
public static ulong ReadUInt64(Stream source)
|
||||
{
|
||||
return ((uint)source.ReadByte() | (ulong)source.ReadByte() << 8 |
|
||||
(ulong)source.ReadByte() << 16 | (ulong)source.ReadByte() << 24 |
|
||||
(ulong)source.ReadByte() << 32 | (ulong)source.ReadByte() << 40 |
|
||||
(ulong)source.ReadByte() << 48 | (ulong)source.ReadByte() << 56);
|
||||
source.Read(buffer, 0, 8);
|
||||
|
||||
return (buffer[0] | (ulong)buffer[1] << 8 |
|
||||
(ulong)buffer[2] << 16 | (ulong)buffer[3] << 24 |
|
||||
(ulong)buffer[4] << 32 | (ulong)buffer[5] << 40 |
|
||||
(ulong)buffer[6] << 48 | (ulong)buffer[7] << 56);
|
||||
}
|
||||
|
||||
public static ulong ReadUInt64BE(Stream source)
|
||||
{
|
||||
return ((ulong)source.ReadByte() << 56 | (ulong)source.ReadByte() << 48 |
|
||||
(ulong)source.ReadByte() << 40 | (ulong)source.ReadByte() << 32 |
|
||||
(ulong)source.ReadByte() << 24 | (ulong)source.ReadByte() << 16 |
|
||||
(ulong)source.ReadByte() << 8 | (uint)source.ReadByte());
|
||||
source.Read(buffer, 0, 8);
|
||||
|
||||
return ((ulong)buffer[0] << 56 | (ulong)buffer[1] << 48 |
|
||||
(ulong)buffer[2] << 40 | (ulong)buffer[3] << 32 |
|
||||
(ulong)buffer[4] << 24 | (ulong)buffer[5] << 16 |
|
||||
(ulong)buffer[6] << 8 | buffer[7]);
|
||||
}
|
||||
|
||||
public static void WriteUInt64(Stream destination, ulong value)
|
||||
{
|
||||
destination.WriteByte((byte)(value));
|
||||
destination.WriteByte((byte)(value >> 8));
|
||||
destination.WriteByte((byte)(value >> 16));
|
||||
destination.WriteByte((byte)(value >> 24));
|
||||
destination.WriteByte((byte)(value >> 32));
|
||||
destination.WriteByte((byte)(value >> 40));
|
||||
destination.WriteByte((byte)(value >> 48));
|
||||
destination.WriteByte((byte)(value >> 56));
|
||||
buffer[0] = (byte)(value);
|
||||
buffer[1] = (byte)(value >> 8);
|
||||
buffer[2] = (byte)(value >> 16);
|
||||
buffer[3] = (byte)(value >> 24);
|
||||
buffer[4] = (byte)(value >> 32);
|
||||
buffer[5] = (byte)(value >> 40);
|
||||
buffer[6] = (byte)(value >> 48);
|
||||
buffer[7] = (byte)(value >> 56);
|
||||
|
||||
destination.Write(buffer, 0, 8);
|
||||
}
|
||||
|
||||
public static void WriteUInt64BE(Stream destination, ulong value)
|
||||
{
|
||||
destination.WriteByte((byte)((value >> 56)));
|
||||
destination.WriteByte((byte)((value >> 48)));
|
||||
destination.WriteByte((byte)((value >> 40)));
|
||||
destination.WriteByte((byte)((value >> 32)));
|
||||
destination.WriteByte((byte)((value >> 24)));
|
||||
destination.WriteByte((byte)((value >> 16)));
|
||||
destination.WriteByte((byte)((value >> 8)));
|
||||
destination.WriteByte((byte)(value));
|
||||
buffer[0] = (byte)((value >> 56));
|
||||
buffer[1] = (byte)((value >> 48));
|
||||
buffer[2] = (byte)((value >> 40));
|
||||
buffer[3] = (byte)((value >> 32));
|
||||
buffer[4] = (byte)((value >> 24));
|
||||
buffer[5] = (byte)((value >> 16));
|
||||
buffer[6] = (byte)((value >> 8));
|
||||
buffer[7] = (byte)(value);
|
||||
|
||||
destination.Write(buffer, 0, 8);
|
||||
}
|
||||
|
||||
public static long ReadInt64(Stream source)
|
||||
{
|
||||
return source.ReadByte() | source.ReadByte() << 8 |
|
||||
source.ReadByte() << 16 | source.ReadByte() << 24 |
|
||||
source.ReadByte() << 32 | source.ReadByte() << 40 |
|
||||
source.ReadByte() << 48 | source.ReadByte() << 56;
|
||||
source.Read(buffer, 0, 8);
|
||||
|
||||
return buffer[0] | buffer[1] << 8 |
|
||||
buffer[2] << 16 | buffer[3] << 24 |
|
||||
buffer[4] << 32 | buffer[5] << 40 |
|
||||
buffer[6] << 48 | buffer[7] << 56;
|
||||
}
|
||||
|
||||
public static long ReadInt64BE(Stream source)
|
||||
{
|
||||
return source.ReadByte() << 56 | source.ReadByte() << 48 |
|
||||
source.ReadByte() << 40 | source.ReadByte() << 32 |
|
||||
source.ReadByte() << 24 | source.ReadByte() << 16 |
|
||||
source.ReadByte() << 8 | source.ReadByte();
|
||||
source.Read(buffer, 0, 8);
|
||||
|
||||
return buffer[0] << 56 | buffer[1] << 48 |
|
||||
buffer[2] << 40 | buffer[3] << 32 |
|
||||
buffer[4] << 24 | buffer[5] << 16 |
|
||||
buffer[6] << 8 | buffer[7];
|
||||
}
|
||||
|
||||
public static void WriteInt64(Stream destination, long value)
|
||||
{
|
||||
destination.WriteByte((byte)(value));
|
||||
destination.WriteByte((byte)(value >> 8));
|
||||
destination.WriteByte((byte)(value >> 16));
|
||||
destination.WriteByte((byte)(value >> 24));
|
||||
destination.WriteByte((byte)(value >> 32));
|
||||
destination.WriteByte((byte)(value >> 40));
|
||||
destination.WriteByte((byte)(value >> 48));
|
||||
destination.WriteByte((byte)(value >> 56));
|
||||
buffer[0] = (byte)(value);
|
||||
buffer[1] = (byte)(value >> 8);
|
||||
buffer[2] = (byte)(value >> 16);
|
||||
buffer[3] = (byte)(value >> 24);
|
||||
buffer[4] = (byte)(value >> 32);
|
||||
buffer[5] = (byte)(value >> 40);
|
||||
buffer[6] = (byte)(value >> 48);
|
||||
buffer[7] = (byte)(value >> 56);
|
||||
|
||||
destination.Write(buffer, 0, 8);
|
||||
}
|
||||
|
||||
public static void WriteInt64BE(Stream destination, long value)
|
||||
{
|
||||
destination.WriteByte((byte)((value >> 56)));
|
||||
destination.WriteByte((byte)((value >> 48)));
|
||||
destination.WriteByte((byte)((value >> 40)));
|
||||
destination.WriteByte((byte)((value >> 32)));
|
||||
destination.WriteByte((byte)((value >> 24)));
|
||||
destination.WriteByte((byte)((value >> 16)));
|
||||
destination.WriteByte((byte)((value >> 8)));
|
||||
destination.WriteByte((byte)(value));
|
||||
buffer[0] = (byte)((value >> 56));
|
||||
buffer[1] = (byte)((value >> 48));
|
||||
buffer[2] = (byte)((value >> 40));
|
||||
buffer[3] = (byte)((value >> 32));
|
||||
buffer[4] = (byte)((value >> 24));
|
||||
buffer[5] = (byte)((value >> 16));
|
||||
buffer[6] = (byte)((value >> 8));
|
||||
buffer[7] = (byte)(value);
|
||||
|
||||
destination.Write(buffer, 0, 8);
|
||||
}
|
||||
|
||||
public static float ReadSingle(Stream source)
|
||||
@ -400,11 +458,11 @@ namespace SonicAudioLib.IO
|
||||
{
|
||||
var characters = new List<byte>();
|
||||
|
||||
byte character = (byte)source.ReadByte();
|
||||
while (character != 0)
|
||||
source.Read(buffer, 0, 1);
|
||||
while (buffer[0] != 0)
|
||||
{
|
||||
characters.Add(character);
|
||||
character = (byte)source.ReadByte();
|
||||
characters.Add(buffer[0]);
|
||||
source.Read(buffer, 0, 1);
|
||||
}
|
||||
|
||||
return encoding.GetString(characters.ToArray());
|
||||
@ -420,7 +478,9 @@ namespace SonicAudioLib.IO
|
||||
byte[] buffer = encoding.GetBytes(value);
|
||||
|
||||
destination.Write(buffer, 0, buffer.Length);
|
||||
destination.WriteByte(0);
|
||||
|
||||
buffer[0] = 0;
|
||||
destination.Write(buffer, 0, 1);
|
||||
}
|
||||
|
||||
public static string ReadCString(Stream source, int length)
|
||||
@ -457,10 +517,15 @@ namespace SonicAudioLib.IO
|
||||
|
||||
public static void Pad(Stream destination, long alignment)
|
||||
{
|
||||
while ((destination.Position % alignment) != 0)
|
||||
long value = destination.Position;
|
||||
|
||||
while ((value % alignment) != 0)
|
||||
{
|
||||
destination.WriteByte(0);
|
||||
value++;
|
||||
}
|
||||
|
||||
byte[] buffer = new byte[value - destination.Position];
|
||||
destination.Write(buffer, 0, buffer.Length);
|
||||
}
|
||||
}
|
||||
}
|
@ -13,7 +13,7 @@ namespace SonicAudioLib.IO
|
||||
private long length = 0;
|
||||
private Encoding encoding = Encoding.Default;
|
||||
|
||||
public static readonly string AdxBlankString = "<NULL>";
|
||||
public const string AdxBlankString = "<NULL>";
|
||||
|
||||
public long Position
|
||||
{
|
||||
@ -51,7 +51,7 @@ namespace SonicAudioLib.IO
|
||||
|
||||
foreach (StringItem item in items)
|
||||
{
|
||||
EndianStream.WriteCString(destination, item.Value, encoding);
|
||||
DataStream.WriteCString(destination, item.Value, encoding);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,18 +4,12 @@ using System.Linq;
|
||||
|
||||
namespace SonicAudioLib.IO
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a <see cref="Stream"/> based substream for viewing a portion of a Stream.
|
||||
/// </summary>
|
||||
public class Substream : Stream
|
||||
public sealed class SubStream : Stream
|
||||
{
|
||||
private Stream baseStream;
|
||||
private long streamPosition;
|
||||
private long streamLength;
|
||||
private long basePosition;
|
||||
private long baseLength;
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the base Stream supports reading.
|
||||
/// </summary>
|
||||
public override bool CanRead
|
||||
{
|
||||
get
|
||||
@ -24,9 +18,6 @@ namespace SonicAudioLib.IO
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the base Stream supports seeking.
|
||||
/// </summary>
|
||||
public override bool CanSeek
|
||||
{
|
||||
get
|
||||
@ -35,84 +26,50 @@ namespace SonicAudioLib.IO
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Always returns false.
|
||||
/// </summary>
|
||||
public override bool CanWrite
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
return baseStream.CanWrite;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the length of the substream.
|
||||
/// </summary>
|
||||
public override long Length
|
||||
{
|
||||
get
|
||||
{
|
||||
return streamLength;
|
||||
return baseLength;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the position of the substream.
|
||||
/// </summary>
|
||||
public override long Position
|
||||
{
|
||||
get
|
||||
{
|
||||
return baseStream.Position - streamPosition;
|
||||
return baseStream.Position - basePosition;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
baseStream.Position = value + streamPosition;
|
||||
baseStream.Position = basePosition + value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the position of the base Stream.
|
||||
/// </summary>
|
||||
public long AbsolutePosition
|
||||
{
|
||||
get
|
||||
{
|
||||
return baseStream.Position;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
baseStream.Position = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Closes the substream.
|
||||
/// </summary>
|
||||
public override void Close()
|
||||
{
|
||||
base.Close();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Does nothing.
|
||||
/// </summary>
|
||||
public override void Flush()
|
||||
{
|
||||
baseStream.Flush();
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (baseStream.Position >= streamPosition + streamLength)
|
||||
if (baseStream.Position >= basePosition + baseLength)
|
||||
{
|
||||
count = 0;
|
||||
}
|
||||
else if (baseStream.Position + count > streamPosition + streamLength)
|
||||
|
||||
else if (baseStream.Position + count > basePosition + baseLength)
|
||||
{
|
||||
count = (int)(streamPosition + streamLength - baseStream.Position);
|
||||
count = (int)(basePosition + baseLength - baseStream.Position);
|
||||
}
|
||||
|
||||
return baseStream.Read(buffer, offset, count);
|
||||
@ -122,79 +79,69 @@ namespace SonicAudioLib.IO
|
||||
{
|
||||
if (origin == SeekOrigin.Begin)
|
||||
{
|
||||
offset += streamPosition;
|
||||
offset += basePosition;
|
||||
}
|
||||
|
||||
else if (origin == SeekOrigin.End)
|
||||
{
|
||||
offset = streamPosition + streamLength - offset;
|
||||
offset = basePosition + baseLength - offset;
|
||||
origin = SeekOrigin.Begin;
|
||||
}
|
||||
|
||||
return baseStream.Seek(offset, origin);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Seeks to the start of the substream.
|
||||
/// </summary>
|
||||
public void SeekToStart()
|
||||
{
|
||||
baseStream.Position = streamPosition;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Throws <see cref="NotSupportedException"/>.
|
||||
/// </summary>
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
baseLength = value;
|
||||
|
||||
/// <summary>
|
||||
/// Throws <see cref="NotSupportedException"/>.
|
||||
/// </summary>
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Throws <see cref="NotSupportedException"/>.
|
||||
/// </summary>
|
||||
public override void WriteByte(byte value)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an array of the data that the substream covers.
|
||||
/// </summary>
|
||||
public byte[] ToArray()
|
||||
{
|
||||
using (MemoryStream destination = new MemoryStream())
|
||||
if (basePosition + baseLength > baseStream.Length)
|
||||
{
|
||||
CopyTo(destination);
|
||||
return destination.ToArray();
|
||||
baseStream.SetLength(basePosition + baseLength);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a substream by the specified base Stream at the specified offset.
|
||||
/// </summary>
|
||||
public Substream(Stream baseStream, long streamPosition) : this(baseStream, streamPosition, baseStream.Length - streamPosition)
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (baseStream.Position >= basePosition + baseLength)
|
||||
{
|
||||
count = 0;
|
||||
}
|
||||
|
||||
else if (baseStream.Position + count > basePosition + baseLength)
|
||||
{
|
||||
count = (int)(basePosition + baseLength - baseStream.Position);
|
||||
}
|
||||
|
||||
baseStream.Write(buffer, 0, count);
|
||||
}
|
||||
|
||||
public byte[] ToArray()
|
||||
{
|
||||
long previousPosition = baseStream.Position;
|
||||
|
||||
baseStream.Seek(basePosition, SeekOrigin.Begin);
|
||||
|
||||
using (MemoryStream memoryStream = new MemoryStream())
|
||||
{
|
||||
CopyTo(memoryStream);
|
||||
|
||||
baseStream.Seek(previousPosition, SeekOrigin.Begin);
|
||||
return memoryStream.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public SubStream(Stream baseStream, long basePosition) : this(baseStream, basePosition, baseStream.Length - basePosition)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a substream by the specified base Stream at the specified offset and with the specified length.
|
||||
/// </summary>
|
||||
public Substream(Stream baseStream, long streamPosition, long streamLength)
|
||||
public SubStream(Stream baseStream, long basePosition, long baseLength)
|
||||
{
|
||||
this.baseStream = baseStream;
|
||||
this.streamPosition = streamPosition;
|
||||
this.streamLength = streamLength;
|
||||
this.basePosition = basePosition;
|
||||
this.baseLength = baseLength;
|
||||
|
||||
SeekToStart();
|
||||
baseStream.Seek(this.basePosition, SeekOrigin.Begin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,8 +9,9 @@
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>SonicAudioLib</RootNamespace>
|
||||
<AssemblyName>SonicAudioLib</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
@ -21,6 +22,7 @@
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AllowUnsafeBlocks>false</AllowUnsafeBlocks>
|
||||
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
@ -30,6 +32,9 @@
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<SignAssembly>false</SignAssembly>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
@ -41,11 +46,11 @@
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Archive\CriAaxArchive.cs" />
|
||||
<Compile Include="Archive\CriAfs2Archive.cs" />
|
||||
<Compile Include="Archive\ArchiveBase.cs" />
|
||||
<Compile Include="Archive\CriCpkArchive.cs" />
|
||||
<Compile Include="Archive\HeroesPacArchive.cs" />
|
||||
<Compile Include="Archives\CriAaxArchive.cs" />
|
||||
<Compile Include="Archives\CriAfs2Archive.cs" />
|
||||
<Compile Include="Archives\ArchiveBase.cs" />
|
||||
<Compile Include="Archives\CriCpkArchive.cs" />
|
||||
<Compile Include="Archives\HeroesPacArchive.cs" />
|
||||
<Compile Include="CriMw\CriTable.cs" />
|
||||
<Compile Include="CriMw\CriField.cs" />
|
||||
<Compile Include="CriMw\CriFieldCollection.cs" />
|
||||
@ -58,13 +63,14 @@
|
||||
<Compile Include="CriMw\CriTableReader.cs" />
|
||||
<Compile Include="CriMw\Serialization\CriTableSerializer.cs" />
|
||||
<Compile Include="CriMw\CriTableWriter.cs" />
|
||||
<Compile Include="IO\EndianStream.cs" />
|
||||
<Compile Include="FileBases\FileXmlBase.cs" />
|
||||
<Compile Include="IO\DataStream.cs" />
|
||||
<Compile Include="IO\DataExtractor.cs" />
|
||||
<Compile Include="IO\StringPool.cs" />
|
||||
<Compile Include="IO\Substream.cs" />
|
||||
<Compile Include="Helpers.cs" />
|
||||
<Compile Include="IO\VldPool.cs" />
|
||||
<Compile Include="Module\ModuleBase.cs" />
|
||||
<Compile Include="IO\SubStream.cs" />
|
||||
<Compile Include="IO\DataPool.cs" />
|
||||
<Compile Include="FileBases\FileBase.cs" />
|
||||
<Compile Include="ProgressChangedEvent.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
|
Loading…
x
Reference in New Issue
Block a user