328 lines
14 KiB
C#
Raw Normal View History

2017-01-26 23:40:46 +03:00
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using CsbBuilder.Project;
using CsbBuilder.BuilderNodes;
2017-01-26 23:40:46 +03:00
using CsbBuilder.Serialization;
using SonicAudioLib.CriMw;
using SonicAudioLib.CriMw.Serialization;
using SonicAudioLib.Archives;
2017-01-26 23:40:46 +03:00
namespace CsbBuilder.Builder
{
public static class CsbBuilder
{
public static void Build(CsbProject project, string outputFileName)
{
CriCpkArchive cpkArchive = new CriCpkArchive();
DirectoryInfo outputDirectory = new DirectoryInfo(Path.GetDirectoryName(outputFileName));
List<SerializationCueSheetTable> cueSheetTables = new List<SerializationCueSheetTable>();
SerializationVersionInfoTable versionInfoTable = new SerializationVersionInfoTable();
cueSheetTables.Add(new SerializationCueSheetTable
{
TableData = CriTableSerializer.Serialize(new List<SerializationVersionInfoTable>() { versionInfoTable }, CriTableWriterSettings.AdxSettings),
Name = "INFO",
TableType = 7,
});
// Serialize cues.
List<SerializationCueTable> cueTables = new List<SerializationCueTable>();
foreach (BuilderCueNode cueNode in project.CueNodes)
{
cueTables.Add(new SerializationCueTable
{
Name = cueNode.Name,
Id = cueNode.Identifier,
UserData = cueNode.UserComment,
Flags = cueNode.Flags,
SynthPath = cueNode.SynthReference,
});
}
cueSheetTables.Add(new SerializationCueSheetTable
{
TableData = CriTableSerializer.Serialize(cueTables, CriTableWriterSettings.AdxSettings),
Name = "CUE",
TableType = 1,
});
// Serialize synth tables.
List<SerializationSynthTable> synthTables = new List<SerializationSynthTable>();
foreach (BuilderSynthNode synthNode in project.SynthNodes)
{
SerializationSynthTable synthTable = new SerializationSynthTable
{
SynthName = synthNode.Name,
SynthType = (byte)synthNode.Type,
ComplexType = (byte)synthNode.PlaybackType,
Volume = synthNode.Volume,
Pitch = synthNode.Pitch,
DelayTime = synthNode.DelayTime,
SControl = synthNode.SControl,
EgDelay = synthNode.EgDelay,
EgAttack = synthNode.EgAttack,
EgHold = synthNode.EgHold,
EgDecay = synthNode.EgDecay,
EgRelease = synthNode.EgRelease,
EgSustain = synthNode.EgSustain,
FType = synthNode.FilterType,
FCof1 = synthNode.FilterCutoff1,
FCof2 = synthNode.FilterCutoff2,
FReso = synthNode.FilterReso,
FReleaseOffset = synthNode.FilterReleaseOffset,
DryOName = synthNode.DryOName,
Mtxrtr = synthNode.Mtxrtr,
Dry0 = synthNode.Dry0,
Dry1 = synthNode.Dry1,
Dry2 = synthNode.Dry2,
Dry3 = synthNode.Dry3,
Dry4 = synthNode.Dry4,
Dry5 = synthNode.Dry5,
Dry6 = synthNode.Dry6,
Dry7 = synthNode.Dry7,
WetOName = synthNode.WetOName,
Wet0 = synthNode.Wet0,
Wet1 = synthNode.Wet1,
Wet2 = synthNode.Wet2,
Wet3 = synthNode.Wet3,
Wet4 = synthNode.Wet4,
Wet5 = synthNode.Wet5,
Wet6 = synthNode.Wet6,
Wet7 = synthNode.Wet7,
Wcnct0 = synthNode.Wcnct0,
Wcnct1 = synthNode.Wcnct1,
Wcnct2 = synthNode.Wcnct2,
Wcnct3 = synthNode.Wcnct3,
Wcnct4 = synthNode.Wcnct4,
Wcnct5 = synthNode.Wcnct5,
Wcnct6 = synthNode.Wcnct6,
Wcnct7 = synthNode.Wcnct7,
VoiceLimitGroupName = synthNode.VoiceLimitGroupReference,
VoiceLimitType = synthNode.VoiceLimitType,
VoiceLimitPriority = synthNode.VoiceLimitPriority,
VoiceLimitPhTime = synthNode.VoiceLimitProhibitionTime,
VoiceLimitPcdlt = synthNode.VoiceLimitPcdlt,
Pan3dVolumeOffset = synthNode.Pan3dVolumeOffset,
Pan3dVolumeGain = synthNode.Pan3dVolumeGain,
Pan3dAngleOffset = synthNode.Pan3dAngleOffset,
Pan3dAngleGain = synthNode.Pan3dAngleGain,
Pan3dDistanceOffset = synthNode.Pan3dDistanceOffset,
Pan3dDistanceGain = synthNode.Pan3dDistanceGain,
Dry0g = synthNode.Dry0g,
Dry1g = synthNode.Dry1g,
Dry2g = synthNode.Dry2g,
Dry3g = synthNode.Dry3g,
Dry4g = synthNode.Dry4g,
Dry5g = synthNode.Dry5g,
Dry6g = synthNode.Dry6g,
Dry7g = synthNode.Dry7g,
Wet0g = synthNode.Wet0g,
Wet1g = synthNode.Wet1g,
Wet2g = synthNode.Wet2g,
Wet3g = synthNode.Wet3g,
Wet4g = synthNode.Wet4g,
Wet5g = synthNode.Wet5g,
Wet6g = synthNode.Wet6g,
Wet7g = synthNode.Wet7g,
F1Type = synthNode.Filter1Type,
F1CofOffset = synthNode.Filter1CutoffOffset,
F1CofGain = synthNode.Filter1CutoffGain,
F1ResoOffset = synthNode.Filter1ResoOffset,
F1ResoGain = synthNode.Filter1ResoGain,
F2Type = synthNode.Filter2Type,
F2CofLowOffset = synthNode.Filter2CutoffLowerOffset,
F2CofLowGain = synthNode.Filter2CutoffLowerGain,
F2CofHighOffset = synthNode.Filter2CutoffHigherOffset,
F2CofHighGain = synthNode.Filter2CutoffHigherGain,
Probability = synthNode.PlaybackProbability,
NumberLmtChildren = synthNode.NLmtChildren,
Repeat = synthNode.Repeat,
ComboTime = synthNode.ComboTime,
ComboLoopBack = synthNode.ComboLoopBack,
};
if (synthNode.Type == BuilderSynthType.Single)
{
synthTable.LinkName = synthNode.SoundElementReference;
}
else if (synthNode.Type == BuilderSynthType.WithChildren)
{
foreach (string trackReference in synthNode.Children)
{
synthTable.LinkName += trackReference + (char)0x0A;
}
}
if (!string.IsNullOrEmpty(synthNode.AisacReference))
{
BuilderAisacNode aisacNode = project.AisacNodes.First(aisac => aisac.Name == synthNode.AisacReference);
synthTable.AisacSetName = aisacNode.AisacName + "::" + aisacNode.Name + (char)0x0A;
}
synthTables.Add(synthTable);
}
cueSheetTables.Add(new SerializationCueSheetTable
{
TableData = CriTableSerializer.Serialize(synthTables, CriTableWriterSettings.AdxSettings),
Name = "SYNTH",
TableType = 2,
});
List<FileInfo> junks = new List<FileInfo>();
// Serialize the sound elements.
List<SerializationSoundElementTable> soundElementTables = new List<SerializationSoundElementTable>();
foreach (BuilderSoundElementNode soundElementNode in project.SoundElementNodes)
{
CriAaxArchive aaxArchive = new CriAaxArchive();
if (!string.IsNullOrEmpty(soundElementNode.Intro))
{
aaxArchive.Add(new CriAaxEntry
{
Flag = CriAaxEntryFlag.Intro,
FilePath = new FileInfo(Path.Combine(project.AudioDirectory.FullName, soundElementNode.Intro)),
});
aaxArchive.SetModeFromExtension(soundElementNode.Intro);
2017-01-26 23:40:46 +03:00
}
if (!string.IsNullOrEmpty(soundElementNode.Loop))
{
aaxArchive.Add(new CriAaxEntry
{
Flag = CriAaxEntryFlag.Loop,
FilePath = new FileInfo(Path.Combine(project.AudioDirectory.FullName, soundElementNode.Loop)),
});
aaxArchive.SetModeFromExtension(soundElementNode.Loop);
2017-01-26 23:40:46 +03:00
}
byte[] data = new byte[0];
if (soundElementNode.Streaming)
{
CriCpkEntry entry = new CriCpkEntry();
entry.Name = Path.GetFileName(soundElementNode.Name);
entry.DirectoryName = Path.GetDirectoryName(soundElementNode.Name);
entry.Id = (uint)cpkArchive.Count;
entry.UpdateDateTime = DateTime.Now;
entry.FilePath = new FileInfo(Path.GetTempFileName());
cpkArchive.Add(entry);
aaxArchive.Save(entry.FilePath.FullName);
junks.Add(entry.FilePath);
}
else
{
data = aaxArchive.Save();
}
soundElementTables.Add(new SerializationSoundElementTable
{
Name = soundElementNode.Name,
Data = data,
FormatType = (byte)aaxArchive.Mode,
2017-01-26 23:40:46 +03:00
SoundFrequency = soundElementNode.SampleRate,
NumberChannels = soundElementNode.ChannelCount,
Streaming = soundElementNode.Streaming,
NumberSamples = soundElementNode.SampleCount,
});
}
cueSheetTables.Add(new SerializationCueSheetTable
{
TableData = CriTableSerializer.Serialize(soundElementTables, CriTableWriterSettings.AdxSettings),
Name = "SOUND_ELEMENT",
TableType = 4,
});
// Serialize the aisacs.
List<SerializationAisacTable> aisacTables = new List<SerializationAisacTable>();
foreach (BuilderAisacNode aisacNode in project.AisacNodes)
{
List<SerializationAisacGraphTable> graphTables = new List<SerializationAisacGraphTable>();
foreach (BuilderAisacGraphNode graphNode in aisacNode.Graphs)
{
List<SerializationAisacPointTable> pointTables = new List<SerializationAisacPointTable>();
foreach (BuilderAisacPointNode pointNode in graphNode.Points)
{
pointTables.Add(new SerializationAisacPointTable
{
In = pointNode.X,
Out = pointNode.Y,
});
}
graphTables.Add(new SerializationAisacGraphTable
{
Points = CriTableSerializer.Serialize(pointTables, CriTableWriterSettings.AdxSettings),
Type = graphNode.Type,
InMax = graphNode.MaximumX,
InMin = graphNode.MinimumX,
OutMax = graphNode.MaximumY,
OutMin = graphNode.MinimumY,
});
}
aisacTables.Add(new SerializationAisacTable
{
Graph = CriTableSerializer.Serialize(graphTables, CriTableWriterSettings.AdxSettings),
Name = aisacNode.AisacName,
PathName = aisacNode.Name,
Type = aisacNode.Type,
RandomRange = aisacNode.RandomRange,
});
}
cueSheetTables.Add(new SerializationCueSheetTable
{
TableData = CriTableSerializer.Serialize(aisacTables, CriTableWriterSettings.AdxSettings),
Name = "ISAAC",
TableType = 5,
});
// Serialize the voice limit groups.
List<SerializationVoiceLimitGroupTable> voiceLimitGroupTables = new List<SerializationVoiceLimitGroupTable>();
foreach (BuilderVoiceLimitGroupNode voiceLimitGroupNode in project.VoiceLimitGroupNodes)
{
voiceLimitGroupTables.Add(new SerializationVoiceLimitGroupTable
{
VoiceLimitGroupName = voiceLimitGroupNode.Name,
VoiceLimitGroupNum = voiceLimitGroupNode.MaxAmountOfInstances,
});
}
cueSheetTables.Add(new SerializationCueSheetTable
{
TableData = CriTableSerializer.Serialize(voiceLimitGroupTables, CriTableWriterSettings.AdxSettings),
Name = "VOICE_LIMIT_GROUP",
TableType = 6,
});
// Finally, serialize the CSB file.
2017-04-17 19:06:29 +03:00
CriTableSerializer.Serialize(outputFileName, cueSheetTables, CriTableWriterSettings.AdxSettings, MainForm.Settings.BufferSize);
2017-01-26 23:40:46 +03:00
if (cpkArchive.Count > 0)
{
2017-04-17 19:06:29 +03:00
cpkArchive.Save(Path.ChangeExtension(outputFileName, "cpk"), MainForm.Settings.BufferSize);
2017-01-26 23:40:46 +03:00
}
foreach (FileInfo junk in junks)
{
junk.Delete();
}
}
}
}