mirror of
https://github.com/blueskythlikesclouds/SonicAudioTools.git
synced 2025-02-09 23:48:25 +01:00
2538 lines
94 KiB
C#
2538 lines
94 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.ComponentModel;
|
||
using System.Data;
|
||
using System.Drawing;
|
||
using System.Linq;
|
||
using System.Text;
|
||
using System.Threading;
|
||
using System.Threading.Tasks;
|
||
using System.Windows.Forms;
|
||
using System.Diagnostics;
|
||
using System.IO;
|
||
using System.Reflection;
|
||
using System.Xml;
|
||
using System.Xml.Serialization;
|
||
using System.Runtime.InteropServices;
|
||
|
||
using CsbBuilder.Builder;
|
||
using CsbBuilder.BuilderNodes;
|
||
using CsbBuilder.Audio;
|
||
using CsbBuilder.Importer;
|
||
using CsbBuilder.Project;
|
||
using CsbBuilder.Serialization;
|
||
using CsbBuilder.Properties;
|
||
|
||
using SonicAudioLib.IO;
|
||
using SonicAudioLib.Archives;
|
||
|
||
using NAudio.Wave;
|
||
|
||
namespace CsbBuilder
|
||
{
|
||
public partial class MainForm : Form
|
||
{
|
||
public static Settings Settings;
|
||
|
||
private bool enabled = false;
|
||
private bool saved = true;
|
||
private CsbProject project = null;
|
||
|
||
private TreeNode copiedNode = null;
|
||
private TreeView treeViewOfCopiedNode = null;
|
||
|
||
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();
|
||
|
||
imageList.Images.Add("Node", Resources.Node);
|
||
imageList.Images.Add("Folder", Resources.Folder);
|
||
imageList.Images.Add("FolderOpen", Resources.FolderOpen);
|
||
imageList.Images.Add("Sound", Resources.Sound);
|
||
|
||
Settings = Settings.Load();
|
||
}
|
||
|
||
public void ClearTreeViews()
|
||
{
|
||
cueTree.Nodes.Clear();
|
||
synthTree.Nodes.Clear();
|
||
soundElementTree.Nodes.Clear();
|
||
aisacTree.Nodes.Clear();
|
||
voiceLimitGroupTree.Nodes.Clear();
|
||
}
|
||
|
||
public void ExpandAllTreeViews()
|
||
{
|
||
cueTree.ExpandAll();
|
||
if (cueTree.Nodes.Count > 0)
|
||
{
|
||
cueTree.Nodes[0].EnsureVisible();
|
||
}
|
||
|
||
synthTree.ExpandAll();
|
||
if (synthTree.Nodes.Count > 0)
|
||
{
|
||
synthTree.Nodes[0].EnsureVisible();
|
||
}
|
||
|
||
soundElementTree.ExpandAll();
|
||
if (soundElementTree.Nodes.Count > 0)
|
||
{
|
||
soundElementTree.Nodes[0].EnsureVisible();
|
||
}
|
||
|
||
aisacTree.ExpandAll();
|
||
if (aisacTree.Nodes.Count > 0)
|
||
{
|
||
aisacTree.Nodes[0].EnsureVisible();
|
||
}
|
||
|
||
voiceLimitGroupTree.ExpandAll();
|
||
if (voiceLimitGroupTree.Nodes.Count > 0)
|
||
{
|
||
voiceLimitGroupTree.Nodes[0].EnsureVisible();
|
||
}
|
||
}
|
||
|
||
public void ClearProject()
|
||
{
|
||
project = null;
|
||
ClearTreeViews();
|
||
Text = Program.ApplicationTitle;
|
||
saved = true;
|
||
}
|
||
|
||
public void DisplayOnTreeView()
|
||
{
|
||
foreach (BuilderCueNode cueNode in project.CueNodes)
|
||
{
|
||
TreeNode treeNode = new TreeNode();
|
||
treeNode.ContextMenuStrip = cueReferenceMenu;
|
||
treeNode.Name = cueNode.Name;
|
||
treeNode.Text = treeNode.Name;
|
||
treeNode.Tag = cueNode;
|
||
cueTree.Nodes.Add(treeNode);
|
||
}
|
||
|
||
foreach (BuilderSynthNode synthNode in project.SynthNodes)
|
||
{
|
||
TreeNode treeNode = synthTree.CreateNodesByFullPath(synthNode.Name);
|
||
treeNode.ContextMenuStrip = trackMenu;
|
||
treeNode.Tag = synthNode;
|
||
|
||
if (synthNode.Type == BuilderSynthType.Single)
|
||
{
|
||
treeNode.ContextMenuStrip = trackItemMenu;
|
||
treeNode.ImageIndex = 3;
|
||
treeNode.SelectedImageIndex = 3;
|
||
}
|
||
|
||
while ((treeNode = treeNode.Parent) != null)
|
||
{
|
||
if (treeNode.Tag == null)
|
||
{
|
||
treeNode.ContextMenuStrip = synthFolderMenu;
|
||
}
|
||
}
|
||
}
|
||
|
||
foreach (BuilderSoundElementNode soundElementNode in project.SoundElementNodes)
|
||
{
|
||
TreeNode treeNode = soundElementTree.CreateNodesByFullPath(soundElementNode.Name);
|
||
treeNode.ContextMenuStrip = soundElementMenu;
|
||
treeNode.Tag = soundElementNode;
|
||
treeNode.ImageIndex = 3;
|
||
treeNode.SelectedImageIndex = 3;
|
||
|
||
while ((treeNode = treeNode.Parent) != null)
|
||
{
|
||
if (treeNode.Tag == null)
|
||
{
|
||
treeNode.ContextMenuStrip = folderMenu;
|
||
}
|
||
}
|
||
}
|
||
|
||
foreach (BuilderAisacNode aisacNode in project.AisacNodes)
|
||
{
|
||
TreeNode treeNode = aisacTree.CreateNodesByFullPath(aisacNode.Name);
|
||
treeNode.ContextMenuStrip = aisacNodeMenu;
|
||
treeNode.Tag = aisacNode;
|
||
|
||
while ((treeNode = treeNode.Parent) != null)
|
||
{
|
||
if (treeNode.Tag == null)
|
||
{
|
||
treeNode.ContextMenuStrip = aisacFolderMenu;
|
||
}
|
||
}
|
||
}
|
||
|
||
foreach (BuilderVoiceLimitGroupNode voiceLimitGroupNode in project.VoiceLimitGroupNodes)
|
||
{
|
||
TreeNode treeNode = new TreeNode();
|
||
treeNode.ContextMenuStrip = nodeMenu;
|
||
treeNode.Name = voiceLimitGroupNode.Name;
|
||
treeNode.Text = treeNode.Name;
|
||
treeNode.Tag = voiceLimitGroupNode;
|
||
voiceLimitGroupTree.Nodes.Add(treeNode);
|
||
}
|
||
}
|
||
|
||
public void SetProject(CsbProject project)
|
||
{
|
||
StopSound(null, null);
|
||
|
||
if (!enabled)
|
||
{
|
||
splitContainer1.Enabled = true;
|
||
splitContainer2.Enabled = true;
|
||
propertyGrid.Enabled = true;
|
||
saveProjectAsToolStripMenuItem.Enabled = true;
|
||
saveProjectToolStripMenuItem.Enabled = true;
|
||
buildCurrentProjectAsToolStripMenuItem.Enabled = true;
|
||
buildCurrentProjectToolStripMenuItem.Enabled = true;
|
||
mergeProjectToolStripMenuItem.Enabled = true;
|
||
ımportAndMergeToolStripMenuItem.Enabled = true;
|
||
enabled = true;
|
||
}
|
||
|
||
ClearProject();
|
||
this.project = project;
|
||
project.Create();
|
||
|
||
DisplayOnTreeView();
|
||
UpdateAllNodes();
|
||
ExpandAllTreeViews();
|
||
|
||
Text += $" - {project.Name}";
|
||
}
|
||
|
||
private void CreateNewProject(object sender, EventArgs e)
|
||
{
|
||
if (AskForSave() == DialogResult.Cancel)
|
||
{
|
||
return;
|
||
}
|
||
|
||
using (CreateNewProjectForm newProject = new CreateNewProjectForm())
|
||
{
|
||
if (newProject.ShowDialog(this) == DialogResult.OK)
|
||
{
|
||
SetProject(newProject.Project);
|
||
project.Save();
|
||
}
|
||
}
|
||
}
|
||
|
||
private void ImportCsbFile(object sender, EventArgs e)
|
||
{
|
||
if (AskForSave() == DialogResult.Cancel)
|
||
{
|
||
return;
|
||
}
|
||
|
||
using (OpenFileDialog openCsbFile = new OpenFileDialog
|
||
{
|
||
Title = "Import CSB File",
|
||
DefaultExt = "csb",
|
||
Filter = "CSB Files|*.csb",
|
||
})
|
||
{
|
||
if (openCsbFile.ShowDialog() == DialogResult.OK)
|
||
{
|
||
using (CreateNewProjectForm createProject = new CreateNewProjectForm(openCsbFile.FileName))
|
||
{
|
||
if (createProject.ShowDialog(this) == DialogResult.OK)
|
||
{
|
||
createProject.Project.Create();
|
||
CsbImporter.Import(openCsbFile.FileName, createProject.Project);
|
||
SetProject(createProject.Project);
|
||
project.Save();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
private void OnNodeClick(object sender, TreeNodeMouseClickEventArgs e)
|
||
{
|
||
e.Node.TreeView.SelectedNode = e.Node;
|
||
}
|
||
|
||
private TreeNode CreateCueNode(TreeNodeCollection collection, TreeNode parent, int nodeIndex = -1)
|
||
{
|
||
saved = false;
|
||
|
||
int index = 0;
|
||
|
||
string parentName = parent != null && Settings.NameNodeAfterParent ? parent.Name : "Cue";
|
||
while (collection.ContainsKey($"{parentName}_{index}"))
|
||
{
|
||
index++;
|
||
}
|
||
|
||
TreeNode treeNode = nodeIndex == -1 ? collection.Add($"{parentName}_{index}") : collection.Insert(nodeIndex, $"{parentName}_{index}");
|
||
treeNode.Name = treeNode.Text;
|
||
treeNode.ContextMenuStrip = cueReferenceMenu;
|
||
BuilderCueNode cueNode = new BuilderCueNode();
|
||
cueNode.Name = treeNode.FullPath;
|
||
|
||
if (project.CueNodes.Count > 0)
|
||
{
|
||
cueNode.Identifier = project.CueNodes.Max(cue => cue.Identifier) + 1;
|
||
}
|
||
|
||
treeNode.Tag = cueNode;
|
||
|
||
project.CueNodes.Add(cueNode);
|
||
|
||
treeNode.TreeView.SelectedNode = treeNode;
|
||
treeNode.EnsureVisible();
|
||
return treeNode;
|
||
}
|
||
|
||
private void RemoveNode(BuilderBaseNode node)
|
||
{
|
||
if (node is BuilderCueNode cueNode)
|
||
{
|
||
project.CueNodes.Remove(cueNode);
|
||
}
|
||
|
||
else if (node is BuilderSynthNode synthNode)
|
||
{
|
||
project.SynthNodes.Remove(synthNode);
|
||
|
||
project.CueNodes.Where(cue => cue.SynthReference == synthNode.Name).ToList().ForEach(cue => cue.SynthReference = string.Empty);
|
||
project.SynthNodes.Where(synth => synth.Children.Contains(synthNode.Name)).ToList().ForEach(synth => synth.Children.Remove(synthNode.Name));
|
||
}
|
||
|
||
else if (node is BuilderSoundElementNode soundElementNode)
|
||
{
|
||
project.SoundElementNodes.Remove(soundElementNode);
|
||
|
||
project.SynthNodes.Where(soundElement => soundElement.SoundElementReference == soundElementNode.Name).ToList().ForEach(synth => synth.SoundElementReference = string.Empty);
|
||
}
|
||
|
||
else if (node is BuilderAisacNode aisacNode)
|
||
{
|
||
project.AisacNodes.Remove(aisacNode);
|
||
|
||
project.SynthNodes.Where(synth => synth.AisacReference == aisacNode.Name).ToList().ForEach(synth => synth.AisacReference = string.Empty);
|
||
}
|
||
|
||
else if (node is BuilderVoiceLimitGroupNode voiceLimitGroupNode)
|
||
{
|
||
project.VoiceLimitGroupNodes.Remove(voiceLimitGroupNode);
|
||
|
||
project.SynthNodes.Where(synth => synth.VoiceLimitGroupReference == voiceLimitGroupNode.Name).ToList().ForEach(voiceLimitGroup => voiceLimitGroup.VoiceLimitGroupReference = string.Empty);
|
||
}
|
||
}
|
||
|
||
private TreeNode CreateSynthNode(TreeNodeCollection collection, TreeNode parent, int nodeIndex = -1)
|
||
{
|
||
saved = false;
|
||
|
||
int index = 0;
|
||
|
||
string parentName = parent != null && Settings.NameNodeAfterParent ? parent.Name : "Synth";
|
||
while (collection.ContainsKey($"{parentName}_{index}"))
|
||
{
|
||
index++;
|
||
}
|
||
|
||
TreeNode treeNode = nodeIndex == -1 ? collection.Add($"{parentName}_{index}") : collection.Insert(nodeIndex, $"{parentName}_{index}");
|
||
treeNode.Name = treeNode.Text;
|
||
treeNode.ContextMenuStrip = trackMenu;
|
||
BuilderSynthNode synthNode = new BuilderSynthNode();
|
||
synthNode.Type = BuilderSynthType.WithChildren;
|
||
synthNode.Name = treeNode.FullPath;
|
||
treeNode.Tag = synthNode;
|
||
project.SynthNodes.Add(synthNode);
|
||
|
||
if (parent != null && parent.Tag is BuilderSynthNode parentSynthNode)
|
||
{
|
||
if (parentSynthNode.Type == BuilderSynthType.WithChildren)
|
||
{
|
||
parentSynthNode.Children.Add(synthNode.Name);
|
||
}
|
||
}
|
||
|
||
treeNode.TreeView.SelectedNode = treeNode;
|
||
treeNode.EnsureVisible();
|
||
return treeNode;
|
||
}
|
||
|
||
private TreeNode CreateSoundNode(TreeNodeCollection collection, TreeNode parent, int nodeIndex = -1)
|
||
{
|
||
saved = false;
|
||
|
||
int index = 0;
|
||
|
||
string parentName = parent != null && Settings.NameNodeAfterParent ? parent.Name : "Sound";
|
||
while (collection.ContainsKey($"{parentName}_{index}"))
|
||
{
|
||
index++;
|
||
}
|
||
|
||
TreeNode treeNode = nodeIndex == -1 ? collection.Add($"{parentName}_{index}") : collection.Insert(nodeIndex, $"{parentName}_{index}");
|
||
treeNode.Name = treeNode.Text;
|
||
treeNode.ContextMenuStrip = trackItemMenu;
|
||
treeNode.ImageIndex = 3;
|
||
treeNode.SelectedImageIndex = 3;
|
||
BuilderSynthNode synthNode = new BuilderSynthNode();
|
||
synthNode.Name = treeNode.FullPath;
|
||
treeNode.Tag = synthNode;
|
||
project.SynthNodes.Add(synthNode);
|
||
|
||
if (parent != null && parent.Tag is BuilderSynthNode parentSynthNode)
|
||
{
|
||
if (parentSynthNode.Type == BuilderSynthType.WithChildren)
|
||
{
|
||
parentSynthNode.Children.Add(synthNode.Name);
|
||
}
|
||
}
|
||
|
||
treeNode.TreeView.SelectedNode = treeNode;
|
||
treeNode.EnsureVisible();
|
||
return treeNode;
|
||
}
|
||
|
||
private TreeNode CreateSoundElementNode(TreeNodeCollection collection, TreeNode parent, int nodeIndex = -1)
|
||
{
|
||
saved = false;
|
||
|
||
int index = 0;
|
||
|
||
string parentName = parent != null && Settings.NameNodeAfterParent ? parent.Name : "SoundElement";
|
||
while (collection.ContainsKey($"{parentName}_{index}"))
|
||
{
|
||
index++;
|
||
}
|
||
|
||
TreeNode treeNode = nodeIndex == -1 ? collection.Add($"{parentName}_{index}") : collection.Insert(nodeIndex, $"{parentName}_{index}");
|
||
treeNode.Name = treeNode.Text;
|
||
treeNode.ContextMenuStrip = soundElementMenu;
|
||
BuilderSoundElementNode soundElementNode = new BuilderSoundElementNode();
|
||
soundElementNode.Name = treeNode.FullPath;
|
||
treeNode.Tag = soundElementNode;
|
||
treeNode.ImageIndex = 3;
|
||
treeNode.SelectedImageIndex = 3;
|
||
project.SoundElementNodes.Add(soundElementNode);
|
||
|
||
treeNode.TreeView.SelectedNode = treeNode;
|
||
treeNode.EnsureVisible();
|
||
return treeNode;
|
||
}
|
||
|
||
private TreeNode CreateAisacNode(TreeNodeCollection collection, TreeNode parent, int nodeIndex = -1, BuilderAisacNode aisacNodeToImport = null)
|
||
{
|
||
saved = false;
|
||
|
||
int index = 0;
|
||
|
||
string parentName = parent != null && Settings.NameNodeAfterParent ? parent.Name : "AISAC";
|
||
while (collection.ContainsKey($"{parentName}_{index}"))
|
||
{
|
||
index++;
|
||
}
|
||
|
||
TreeNode treeNode = nodeIndex == -1 ? collection.Add($"{parentName}_{index}") : collection.Insert(nodeIndex, $"{parentName}_{index}");
|
||
treeNode.Name = treeNode.Text;
|
||
treeNode.ContextMenuStrip = aisacNodeMenu;
|
||
BuilderAisacNode aisacNode = aisacNodeToImport != null ? aisacNodeToImport : new BuilderAisacNode();
|
||
aisacNode.Name = treeNode.FullPath;
|
||
treeNode.Tag = aisacNode;
|
||
project.AisacNodes.Add(aisacNode);
|
||
|
||
treeNode.TreeView.SelectedNode = treeNode;
|
||
treeNode.EnsureVisible();
|
||
return treeNode;
|
||
}
|
||
|
||
private TreeNode CreateVoiceLimitGroupNode(TreeNodeCollection collection, TreeNode parent, int nodeIndex = -1)
|
||
{
|
||
saved = false;
|
||
|
||
int index = 0;
|
||
|
||
string parentName = parent != null && Settings.NameNodeAfterParent ? parent.Name : "VoiceLimitGroup";
|
||
while (collection.ContainsKey($"{parentName}_{index}"))
|
||
{
|
||
index++;
|
||
}
|
||
|
||
TreeNode treeNode = nodeIndex == -1 ? collection.Add($"{parentName}_{index}") : collection.Insert(nodeIndex, $"{parentName}_{index}");
|
||
treeNode.Name = treeNode.Text;
|
||
treeNode.ContextMenuStrip = nodeMenu;
|
||
BuilderVoiceLimitGroupNode voiceLimitGroup = new BuilderVoiceLimitGroupNode();
|
||
voiceLimitGroup.Name = treeNode.FullPath;
|
||
treeNode.Tag = voiceLimitGroup;
|
||
project.VoiceLimitGroupNodes.Add(voiceLimitGroup);
|
||
|
||
treeNode.TreeView.SelectedNode = treeNode;
|
||
treeNode.EnsureVisible();
|
||
return treeNode;
|
||
}
|
||
|
||
private TreeNode CreateFolder(TreeNodeCollection collection, TreeNode parent)
|
||
{
|
||
saved = false;
|
||
|
||
int index = 0;
|
||
|
||
string parentName = parent != null && Settings.NameNodeAfterParent ? parent.Name : "Folder";
|
||
while (collection.ContainsKey($"Folder_{index}"))
|
||
{
|
||
index++;
|
||
}
|
||
|
||
TreeNode treeNode = collection.Add($"Folder_{index}");
|
||
treeNode.Name = treeNode.Text;
|
||
treeNode.ContextMenuStrip = folderMenu;
|
||
treeNode.ImageIndex = 1;
|
||
treeNode.SelectedImageIndex = 2;
|
||
|
||
treeNode.TreeView.SelectedNode = treeNode;
|
||
treeNode.EnsureVisible();
|
||
return treeNode;
|
||
}
|
||
|
||
private TreeNode CreateSynthFolder(TreeNodeCollection collection)
|
||
{
|
||
saved = false;
|
||
|
||
int index = 0;
|
||
|
||
while (collection.ContainsKey($"Folder_{index}"))
|
||
{
|
||
index++;
|
||
}
|
||
|
||
TreeNode treeNode = collection.Add($"Folder_{index}");
|
||
treeNode.Name = treeNode.Text;
|
||
treeNode.ContextMenuStrip = synthFolderMenu;
|
||
treeNode.ImageIndex = 1;
|
||
treeNode.SelectedImageIndex = 2;
|
||
|
||
treeNode.TreeView.SelectedNode = treeNode;
|
||
treeNode.EnsureVisible();
|
||
return treeNode;
|
||
}
|
||
|
||
private void CreateChildNode(object sender, EventArgs e)
|
||
{
|
||
ContextMenuStrip menuStrip = (ContextMenuStrip)((ToolStripItem)sender).Owner;
|
||
|
||
if (menuStrip.SourceControl is TreeView selectedTree)
|
||
{
|
||
TreeNode selectedNode = selectedTree.SelectedNode;
|
||
|
||
if (selectedTree == cueTree)
|
||
{
|
||
CreateCueNode(selectedTree.Nodes, null);
|
||
}
|
||
|
||
else if (selectedTree == synthTree)
|
||
{
|
||
if (selectedNode.Tag is BuilderSynthNode synthNode && synthNode.Type == BuilderSynthType.WithChildren)
|
||
{
|
||
CreateSoundNode(selectedNode.Nodes, selectedNode);
|
||
}
|
||
|
||
else
|
||
{
|
||
CreateSynthNode(selectedNode.Nodes, selectedNode);
|
||
}
|
||
}
|
||
|
||
else if (selectedTree == soundElementTree)
|
||
{
|
||
CreateSoundElementNode(selectedNode.Nodes, selectedNode);
|
||
}
|
||
|
||
else if (selectedTree == aisacTree)
|
||
{
|
||
CreateAisacNode(selectedNode.Nodes, selectedNode);
|
||
}
|
||
|
||
else if (selectedTree == voiceLimitGroupTree)
|
||
{
|
||
CreateVoiceLimitGroupNode(selectedTree.Nodes, null);
|
||
}
|
||
}
|
||
}
|
||
|
||
private void CreateNode(object sender, EventArgs e)
|
||
{
|
||
ContextMenuStrip menuStrip = (ContextMenuStrip)((ToolStripItem)sender).Owner;
|
||
|
||
if (menuStrip.SourceControl is TreeView selectedTree)
|
||
{
|
||
if (selectedTree == cueTree)
|
||
{
|
||
CreateCueNode(selectedTree.Nodes, null);
|
||
}
|
||
|
||
else if (selectedTree == synthTree)
|
||
{
|
||
CreateSynthNode(selectedTree.Nodes, null);
|
||
}
|
||
|
||
else if (selectedTree == soundElementTree)
|
||
{
|
||
CreateSoundElementNode(selectedTree.Nodes, null);
|
||
}
|
||
|
||
else if (selectedTree == aisacTree)
|
||
{
|
||
CreateAisacNode(selectedTree.Nodes, null);
|
||
}
|
||
|
||
else if (selectedTree == voiceLimitGroupTree)
|
||
{
|
||
CreateVoiceLimitGroupNode(selectedTree.Nodes, null);
|
||
}
|
||
}
|
||
}
|
||
|
||
private void CreateFolder(object sender, EventArgs e)
|
||
{
|
||
ContextMenuStrip menuStrip = (ContextMenuStrip)((ToolStripItem)sender).Owner;
|
||
|
||
if (menuStrip.SourceControl is TreeView selectedTree)
|
||
{
|
||
if (selectedTree == synthTree)
|
||
{
|
||
CreateSynthFolder(selectedTree.Nodes);
|
||
}
|
||
|
||
else
|
||
{
|
||
CreateFolder(selectedTree.Nodes, null);
|
||
}
|
||
}
|
||
}
|
||
|
||
private void RemoveNodes(TreeNodeCollection collection)
|
||
{
|
||
foreach (TreeNode node in collection)
|
||
{
|
||
if (node.Tag is BuilderBaseNode baseNode)
|
||
{
|
||
RemoveNode(baseNode);
|
||
}
|
||
|
||
RemoveNodes(node.Nodes);
|
||
}
|
||
}
|
||
|
||
private void RemoveNode(TreeNode treeNode)
|
||
{
|
||
saved = false;
|
||
|
||
if (treeNode.Tag is BuilderBaseNode baseNode)
|
||
{
|
||
RemoveNode(baseNode);
|
||
}
|
||
|
||
RemoveNodes(treeNode.Nodes);
|
||
treeNode.Remove();
|
||
}
|
||
|
||
private void RemoveNode(object sender, EventArgs e)
|
||
{
|
||
saved = false;
|
||
|
||
ContextMenuStrip menuStrip = (ContextMenuStrip)((ToolStripItem)sender).Owner;
|
||
|
||
if (menuStrip.SourceControl is TreeView selectedTree)
|
||
{
|
||
TreeNode selectedNode = selectedTree.SelectedNode;
|
||
|
||
RemoveNode(selectedNode);
|
||
}
|
||
}
|
||
|
||
private void BuildProject(object sender, EventArgs e)
|
||
{
|
||
project.BinaryDirectory.Create();
|
||
project.Order(cueTree, synthTree, soundElementTree, aisacTree, voiceLimitGroupTree);
|
||
Builder.CsbBuilder.Build(project, Path.Combine(project.BinaryDirectory.FullName, project.Name + ".csb"));
|
||
|
||
Process.Start(project.BinaryDirectory.FullName);
|
||
}
|
||
|
||
private void CopyFullPath(object sender, EventArgs e)
|
||
{
|
||
ContextMenuStrip menuStrip = (ContextMenuStrip)((ToolStripItem)sender).Owner;
|
||
|
||
if (menuStrip.SourceControl is TreeView selectedTree)
|
||
{
|
||
TreeNode selectedNode = selectedTree.SelectedNode;
|
||
|
||
Clipboard.SetText(selectedNode.FullPath);
|
||
}
|
||
}
|
||
|
||
private void CreateChildFolder(object sender, EventArgs e)
|
||
{
|
||
ContextMenuStrip menuStrip = (ContextMenuStrip)((ToolStripItem)sender).Owner;
|
||
|
||
if (menuStrip.SourceControl is TreeView selectedTree)
|
||
{
|
||
TreeNode selectedNode = selectedTree.SelectedNode;
|
||
|
||
if (selectedTree == synthTree)
|
||
{
|
||
CreateSynthFolder(selectedNode.Nodes);
|
||
}
|
||
|
||
else
|
||
{
|
||
CreateFolder(selectedNode.Nodes, selectedNode);
|
||
}
|
||
}
|
||
}
|
||
|
||
private void RenameNode(object sender, TreeNodeMouseClickEventArgs e)
|
||
{
|
||
e.Node.BeginEdit();
|
||
}
|
||
|
||
private void UpdateNodeNoRename(TreeNode treeNode)
|
||
{
|
||
if (treeNode.Tag is BuilderBaseNode baseNode)
|
||
{
|
||
baseNode.Name = treeNode.FullPath;
|
||
}
|
||
|
||
foreach (TreeNode childNode in treeNode.Nodes)
|
||
{
|
||
UpdateNodeNoRename(childNode);
|
||
}
|
||
}
|
||
|
||
private void UpdateNodes(TreeNodeCollection collection)
|
||
{
|
||
foreach (TreeNode treeNode in collection)
|
||
{
|
||
if (treeNode.Tag is BuilderBaseNode baseNode)
|
||
{
|
||
string previousName = baseNode.Name;
|
||
baseNode.Name = treeNode.FullPath;
|
||
|
||
// Do it only if it's different, don't waste time
|
||
if (previousName != baseNode.Name)
|
||
{
|
||
string fullPath = baseNode.Name;
|
||
if (baseNode is BuilderSynthNode)
|
||
{
|
||
project.CueNodes.Where(cue => cue.SynthReference == previousName).ToList().ForEach(cue => cue.SynthReference = fullPath);
|
||
project.SynthNodes.Where(synth => synth.Children.Contains(previousName)).ToList().ForEach(synth => synth.Children[synth.Children.IndexOf(previousName)] = fullPath);
|
||
}
|
||
|
||
else if (baseNode is BuilderSoundElementNode)
|
||
{
|
||
project.SynthNodes.Where(synth => synth.SoundElementReference == previousName).ToList().ForEach(synth => synth.SoundElementReference = fullPath);
|
||
}
|
||
|
||
else if (baseNode is BuilderAisacNode)
|
||
{
|
||
project.SynthNodes.Where(synth => synth.AisacReference == previousName).ToList().ForEach(synth => synth.AisacReference = fullPath);
|
||
}
|
||
|
||
else if (baseNode is BuilderVoiceLimitGroupNode)
|
||
{
|
||
project.SynthNodes.Where(synth => synth.VoiceLimitGroupReference == previousName).ToList().ForEach(synth => synth.VoiceLimitGroupReference = fullPath);
|
||
}
|
||
}
|
||
}
|
||
|
||
else
|
||
{
|
||
treeNode.ImageIndex = 1;
|
||
treeNode.SelectedImageIndex = 2;
|
||
}
|
||
|
||
UpdateNodes(treeNode.Nodes);
|
||
}
|
||
}
|
||
|
||
private void UpdateAllNodes()
|
||
{
|
||
UpdateNodes(cueTree.Nodes);
|
||
UpdateNodes(synthTree.Nodes);
|
||
UpdateNodes(soundElementTree.Nodes);
|
||
UpdateNodes(aisacTree.Nodes);
|
||
UpdateNodes(voiceLimitGroupTree.Nodes);
|
||
}
|
||
|
||
private void RenameNode(TreeNode node, string name)
|
||
{
|
||
saved = false;
|
||
string previousName = node.FullPath;
|
||
|
||
// check siblings before rename
|
||
TreeNodeCollection collection = node.Parent != null ? node.Parent.Nodes : node.TreeView.Nodes;
|
||
|
||
if (collection.ContainsKey(name))
|
||
{
|
||
int index = -1;
|
||
string _name = name;
|
||
while (collection.ContainsKey(name))
|
||
{
|
||
name = $"{_name}_{++index}";
|
||
}
|
||
}
|
||
|
||
node.Name = name;
|
||
node.Text = name;
|
||
|
||
string fullPath = node.FullPath;
|
||
|
||
UpdateAllNodes();
|
||
|
||
if (node.Tag is BuilderSynthNode)
|
||
{
|
||
project.CueNodes.Where(cue => cue.SynthReference == previousName).ToList().ForEach(cue => cue.SynthReference = fullPath);
|
||
project.SynthNodes.Where(synth => synth.Children.Contains(previousName)).ToList().ForEach(synth => synth.Children[synth.Children.IndexOf(previousName)] = fullPath);
|
||
}
|
||
|
||
else if (node.Tag is BuilderSoundElementNode)
|
||
{
|
||
project.SynthNodes.Where(synth => synth.SoundElementReference == previousName).ToList().ForEach(synth => synth.SoundElementReference = fullPath);
|
||
}
|
||
|
||
else if (node.Tag is BuilderAisacNode)
|
||
{
|
||
project.SynthNodes.Where(synth => synth.AisacReference == previousName).ToList().ForEach(synth => synth.AisacReference = fullPath);
|
||
}
|
||
|
||
else if (node.Tag is BuilderVoiceLimitGroupNode)
|
||
{
|
||
project.SynthNodes.Where(synth => synth.VoiceLimitGroupReference == previousName).ToList().ForEach(synth => synth.VoiceLimitGroupReference = fullPath);
|
||
}
|
||
|
||
propertyGrid.Refresh();
|
||
}
|
||
|
||
private void OnRenameEnd(object sender, NodeLabelEditEventArgs e)
|
||
{
|
||
if (string.IsNullOrEmpty(e.Label) || e.Label == e.Node.Name)
|
||
{
|
||
e.CancelEdit = true;
|
||
return;
|
||
}
|
||
|
||
RenameNode(e.Node, e.Label);
|
||
}
|
||
|
||
private void OnPropertyChange(object s, PropertyValueChangedEventArgs e)
|
||
{
|
||
saved = false;
|
||
propertyGrid.Refresh();
|
||
}
|
||
|
||
private DialogResult AskForSave()
|
||
{
|
||
DialogResult dialogResult = DialogResult.No;
|
||
|
||
if (!saved)
|
||
{
|
||
dialogResult = MessageBox.Show("Do you want to save your changes?", "CSB Builder", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Warning);
|
||
|
||
if (dialogResult == DialogResult.Yes)
|
||
{
|
||
SaveProject(null, null);
|
||
}
|
||
}
|
||
|
||
return dialogResult;
|
||
}
|
||
|
||
private void LoadProject(object sender, EventArgs e)
|
||
{
|
||
if (AskForSave() == DialogResult.Cancel)
|
||
{
|
||
return;
|
||
}
|
||
|
||
using (OpenFileDialog openProject = new OpenFileDialog
|
||
{
|
||
Title = "Open CSB Project File",
|
||
Filter = "CSB Project files|*.csbproject",
|
||
DefaultExt = "csbproject",
|
||
})
|
||
{
|
||
if (openProject.ShowDialog() == DialogResult.OK)
|
||
{
|
||
CsbProject csbProject = CsbProject.Load(openProject.FileName);
|
||
|
||
if (!csbProject.AudioDirectory.Exists)
|
||
{
|
||
MessageBox.Show("Audio directory does not seem to be present for this project. All the audio references will be removed.");
|
||
csbProject.SoundElementNodes.ForEach(soundElementNode => soundElementNode.Intro = string.Empty);
|
||
csbProject.SoundElementNodes.ForEach(soundElementNode => soundElementNode.Loop = string.Empty);
|
||
}
|
||
|
||
SetProject(csbProject);
|
||
}
|
||
}
|
||
}
|
||
|
||
private void SaveProject(object sender, EventArgs e)
|
||
{
|
||
project.Order(cueTree, synthTree, soundElementTree, aisacTree, voiceLimitGroupTree);
|
||
project.Save();
|
||
saved = true;
|
||
}
|
||
|
||
private void SaveProjectAs(object sender, EventArgs e)
|
||
{
|
||
using (SaveFileDialog saveProject = new SaveFileDialog
|
||
{
|
||
Title = "Save CSB Project File As",
|
||
Filter = "CSB Project files|*.csbproject",
|
||
DefaultExt = "csbproject",
|
||
})
|
||
{
|
||
if (saveProject.ShowDialog() == DialogResult.OK)
|
||
{
|
||
project.Order(cueTree, synthTree, soundElementTree, aisacTree, voiceLimitGroupTree);
|
||
project.SaveAs(saveProject.FileName);
|
||
saved = true;
|
||
|
||
// Reload the project
|
||
SetProject(project);
|
||
}
|
||
}
|
||
}
|
||
|
||
private void OnClose(object sender, FormClosingEventArgs e)
|
||
{
|
||
if (AskForSave() == DialogResult.Cancel)
|
||
{
|
||
e.Cancel = true;
|
||
}
|
||
}
|
||
|
||
private void Exit(object sender, EventArgs e)
|
||
{
|
||
Close();
|
||
}
|
||
|
||
private void BuildProjectAs(object sender, EventArgs e)
|
||
{
|
||
using (SaveFileDialog buildCsb = new SaveFileDialog()
|
||
{
|
||
Title = "Build Current Project As",
|
||
DefaultExt = "csb",
|
||
Filter = "CSB Files|*.csb",
|
||
FileName = project.Name,
|
||
})
|
||
{
|
||
if (buildCsb.ShowDialog() == DialogResult.OK)
|
||
{
|
||
project.Order(cueTree, synthTree, soundElementTree, aisacTree, voiceLimitGroupTree);
|
||
Builder.CsbBuilder.Build(project, buildCsb.FileName);
|
||
}
|
||
}
|
||
}
|
||
|
||
private void AfterNodeSelect(object sender, TreeViewEventArgs e)
|
||
{
|
||
propertyGrid.SelectedObject = e.Node.Tag;
|
||
}
|
||
|
||
private void MergeProject(object sender, EventArgs e)
|
||
{
|
||
using (OpenFileDialog openProject = new OpenFileDialog
|
||
{
|
||
Title = "Merge Project With",
|
||
Filter = "CSB Project files|*.csbproject",
|
||
DefaultExt = "csbproject",
|
||
})
|
||
{
|
||
if (openProject.ShowDialog() == DialogResult.OK)
|
||
{
|
||
CsbProject csbProject = CsbProject.Load(openProject.FileName);
|
||
|
||
if (!csbProject.AudioDirectory.Exists)
|
||
{
|
||
MessageBox.Show("Audio directory does not seem to be present for this project. All the audio references will be removed.");
|
||
csbProject.SoundElementNodes.ForEach(soundElementNode => soundElementNode.Intro = string.Empty);
|
||
csbProject.SoundElementNodes.ForEach(soundElementNode => soundElementNode.Loop = string.Empty);
|
||
}
|
||
|
||
else
|
||
{
|
||
// Copy all to this project's audio folder
|
||
foreach (FileInfo audioFile in csbProject.AudioDirectory.EnumerateFiles())
|
||
{
|
||
audioFile.CopyTo(Path.Combine(project.AudioDirectory.FullName, audioFile.Name), true);
|
||
}
|
||
}
|
||
|
||
project.CueNodes.AddRange(csbProject.CueNodes);
|
||
project.SynthNodes.AddRange(csbProject.SynthNodes);
|
||
project.SoundElementNodes.AddRange(csbProject.SoundElementNodes);
|
||
project.AisacNodes.AddRange(csbProject.AisacNodes);
|
||
project.VoiceLimitGroupNodes.AddRange(csbProject.VoiceLimitGroupNodes);
|
||
|
||
// Reload
|
||
SetProject(project);
|
||
}
|
||
}
|
||
}
|
||
|
||
private void ImportAndMergeProject(object sender, EventArgs e)
|
||
{
|
||
using (OpenFileDialog openCsbFile = new OpenFileDialog
|
||
{
|
||
Title = "Import And Merge CSB File With",
|
||
DefaultExt = "csb",
|
||
Filter = "CSB Files|*.csb",
|
||
})
|
||
{
|
||
if (openCsbFile.ShowDialog() == DialogResult.OK)
|
||
{
|
||
CsbProject csbProject = new CsbProject();
|
||
csbProject.Directory = project.Directory;
|
||
CsbImporter.Import(openCsbFile.FileName, csbProject);
|
||
|
||
project.CueNodes.AddRange(csbProject.CueNodes);
|
||
project.SynthNodes.AddRange(csbProject.SynthNodes);
|
||
project.SoundElementNodes.AddRange(csbProject.SoundElementNodes);
|
||
project.AisacNodes.AddRange(csbProject.AisacNodes);
|
||
project.VoiceLimitGroupNodes.AddRange(csbProject.VoiceLimitGroupNodes);
|
||
|
||
// Reload
|
||
SetProject(project);
|
||
}
|
||
}
|
||
}
|
||
|
||
private void OnKeyDown(object sender, KeyEventArgs e)
|
||
{
|
||
TreeView treeView = (TreeView)sender;
|
||
|
||
if (e.KeyCode == Keys.Delete && treeView.SelectedNode != null)
|
||
{
|
||
RemoveNode(treeView.SelectedNode);
|
||
}
|
||
|
||
else if (e.Control && e.KeyCode == Keys.C && treeView.SelectedNode != null)
|
||
{
|
||
CopyNode(treeView.SelectedNode);
|
||
}
|
||
|
||
else if (e.Control && e.KeyCode == Keys.V && treeView == treeViewOfCopiedNode)
|
||
{
|
||
if (treeView.SelectedNode == null)
|
||
{
|
||
PasteNode();
|
||
}
|
||
|
||
else if (treeView.SelectedNode != null && (treeView.SelectedNode.Tag == null || (treeView.SelectedNode.Tag is BuilderSynthNode synthNode && synthNode.Type == BuilderSynthType.WithChildren)))
|
||
{
|
||
PasteAsChildNode(treeView.SelectedNode);
|
||
}
|
||
|
||
else if (treeView.SelectedNode != null && treeView.SelectedNode.Tag != null)
|
||
{
|
||
PasteNode(treeView.SelectedNode.Index + 1);
|
||
}
|
||
}
|
||
|
||
else if (e.KeyCode == Keys.Enter && treeView.SelectedNode != null)
|
||
{
|
||
treeView.SelectedNode.BeginEdit();
|
||
}
|
||
}
|
||
|
||
private bool CheckIfAny(TreeView treeView)
|
||
{
|
||
foreach (TreeNode treeNode in treeView.Nodes)
|
||
{
|
||
if (CheckIfAny(treeNode))
|
||
{
|
||
return true;
|
||
}
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
private bool CheckIfAny(TreeNode treeNode)
|
||
{
|
||
if (treeNode.Tag != null)
|
||
{
|
||
return true;
|
||
}
|
||
|
||
foreach (TreeNode childNode in treeNode.Nodes)
|
||
{
|
||
if (CheckIfAny(childNode))
|
||
{
|
||
return true;
|
||
}
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
private void SetAisacReference(object sender, EventArgs e)
|
||
{
|
||
if (!CheckIfAny(aisacTree))
|
||
{
|
||
MessageBox.Show("This project does not contain any Aisac nodes.", "CSB Builder", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||
return;
|
||
}
|
||
|
||
using (SetReferenceForm setReferenceForm = new SetReferenceForm(aisacTree))
|
||
{
|
||
if (setReferenceForm.ShowDialog(this) == DialogResult.OK)
|
||
{
|
||
ContextMenuStrip menuStrip = (ContextMenuStrip)((ToolStripItem)sender).Owner;
|
||
|
||
if (menuStrip.SourceControl is TreeView selectedTree)
|
||
{
|
||
TreeNode selectedNode = selectedTree.SelectedNode;
|
||
|
||
if (selectedNode.Tag is BuilderSynthNode synthNode)
|
||
{
|
||
if (setReferenceForm.SelectedNode == null)
|
||
{
|
||
synthNode.AisacReference = string.Empty;
|
||
}
|
||
|
||
else
|
||
{
|
||
synthNode.AisacReference = setReferenceForm.SelectedNode.FullPath;
|
||
}
|
||
}
|
||
|
||
saved = false;
|
||
propertyGrid.Refresh();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
private void SetVoiceLimitGroupReference(object sender, EventArgs e)
|
||
{
|
||
if (voiceLimitGroupTree.Nodes.Count == 0)
|
||
{
|
||
MessageBox.Show("This project does not contain any Voice Limit Group nodes.", "CSB Builder", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||
return;
|
||
}
|
||
|
||
using (SetReferenceForm setReferenceForm = new SetReferenceForm(voiceLimitGroupTree))
|
||
{
|
||
if (setReferenceForm.ShowDialog(this) == DialogResult.OK)
|
||
{
|
||
ContextMenuStrip menuStrip = (ContextMenuStrip)((ToolStripItem)sender).Owner;
|
||
|
||
if (menuStrip.SourceControl is TreeView selectedTree)
|
||
{
|
||
TreeNode selectedNode = selectedTree.SelectedNode;
|
||
|
||
if (selectedNode.Tag is BuilderSynthNode synthNode)
|
||
{
|
||
if (setReferenceForm.SelectedNode == null)
|
||
{
|
||
synthNode.VoiceLimitGroupReference = string.Empty;
|
||
}
|
||
|
||
else
|
||
{
|
||
synthNode.VoiceLimitGroupReference = setReferenceForm.SelectedNode.FullPath;
|
||
}
|
||
}
|
||
|
||
saved = false;
|
||
propertyGrid.Refresh();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
private void SetSynthReference(object sender, EventArgs e)
|
||
{
|
||
if (!CheckIfAny(synthTree))
|
||
{
|
||
MessageBox.Show("This project does not contain any Synth nodes.", "CSB Builder", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||
return;
|
||
}
|
||
|
||
using (SetReferenceForm setReferenceForm = new SetReferenceForm(synthTree))
|
||
{
|
||
if (setReferenceForm.ShowDialog(this) == DialogResult.OK)
|
||
{
|
||
ContextMenuStrip menuStrip = (ContextMenuStrip)((ToolStripItem)sender).Owner;
|
||
|
||
if (menuStrip.SourceControl is TreeView selectedTree)
|
||
{
|
||
TreeNode selectedNode = selectedTree.SelectedNode;
|
||
|
||
if (selectedNode.Tag is BuilderCueNode)
|
||
{
|
||
BuilderCueNode cueNode = (BuilderCueNode)selectedNode.Tag;
|
||
|
||
if (setReferenceForm.SelectedNode == null)
|
||
{
|
||
cueNode.SynthReference = string.Empty;
|
||
}
|
||
|
||
else
|
||
{
|
||
cueNode.SynthReference = setReferenceForm.SelectedNode.FullPath;
|
||
}
|
||
}
|
||
|
||
saved = false;
|
||
propertyGrid.Refresh();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
private void SelectSynthReference(object sender, EventArgs e)
|
||
{
|
||
ContextMenuStrip menuStrip = (ContextMenuStrip)((ToolStripItem)sender).Owner;
|
||
|
||
if (menuStrip.SourceControl is TreeView selectedTree)
|
||
{
|
||
TreeNode selectedNode = selectedTree.SelectedNode;
|
||
|
||
if (selectedNode.Tag is BuilderCueNode cueNode)
|
||
{
|
||
if (!string.IsNullOrEmpty(cueNode.SynthReference))
|
||
{
|
||
TreeNode treeNode = synthTree.FindNodeByFullPath(cueNode.SynthReference);
|
||
|
||
synthTree.SelectedNode = treeNode;
|
||
treeNode.EnsureVisible();
|
||
synthTree.Focus();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
private void SelectAisacReference(object sender, EventArgs e)
|
||
{
|
||
ContextMenuStrip menuStrip = (ContextMenuStrip)((ToolStripItem)sender).Owner;
|
||
|
||
if (menuStrip.SourceControl is TreeView selectedTree)
|
||
{
|
||
TreeNode selectedNode = selectedTree.SelectedNode;
|
||
|
||
if (selectedNode.Tag is BuilderSynthNode synthNode)
|
||
{
|
||
if (!string.IsNullOrEmpty(synthNode.AisacReference))
|
||
{
|
||
TreeNode treeNode = aisacTree.FindNodeByFullPath(synthNode.AisacReference);
|
||
|
||
tabControl1.SelectTab(tabPage1);
|
||
aisacTree.SelectedNode = treeNode;
|
||
treeNode.EnsureVisible();
|
||
aisacTree.Focus();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
private void SelectVoiceLimitGroupReference(object sender, EventArgs e)
|
||
{
|
||
ContextMenuStrip menuStrip = (ContextMenuStrip)((ToolStripItem)sender).Owner;
|
||
|
||
if (menuStrip.SourceControl is TreeView selectedTree)
|
||
{
|
||
TreeNode selectedNode = selectedTree.SelectedNode;
|
||
|
||
if (selectedNode.Tag is BuilderSynthNode synthNode)
|
||
{
|
||
if (!string.IsNullOrEmpty(synthNode.VoiceLimitGroupReference))
|
||
{
|
||
TreeNode treeNode = voiceLimitGroupTree.FindNodeByFullPath(synthNode.VoiceLimitGroupReference);
|
||
|
||
tabControl1.SelectTab(tabPage2);
|
||
voiceLimitGroupTree.SelectedNode = treeNode;
|
||
treeNode.EnsureVisible();
|
||
voiceLimitGroupTree.Focus();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
private void SelectSoundElementReference(object sender, EventArgs e)
|
||
{
|
||
ContextMenuStrip menuStrip = (ContextMenuStrip)((ToolStripItem)sender).Owner;
|
||
|
||
if (menuStrip.SourceControl is TreeView selectedTree)
|
||
{
|
||
TreeNode selectedNode = selectedTree.SelectedNode;
|
||
|
||
if (selectedNode.Tag is BuilderSynthNode synthNode)
|
||
{
|
||
if (!string.IsNullOrEmpty(synthNode.SoundElementReference))
|
||
{
|
||
TreeNode treeNode = soundElementTree.FindNodeByFullPath(synthNode.SoundElementReference);
|
||
|
||
soundElementTree.SelectedNode = treeNode;
|
||
treeNode.EnsureVisible();
|
||
soundElementTree.Focus();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
private void SetSoundElementReference(object sender, EventArgs e)
|
||
{
|
||
if (!CheckIfAny(soundElementTree))
|
||
{
|
||
MessageBox.Show("This project does not contain any Sound nodes.", "CSB Builder", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||
return;
|
||
}
|
||
|
||
using (SetReferenceForm setReferenceForm = new SetReferenceForm(soundElementTree))
|
||
{
|
||
if (setReferenceForm.ShowDialog(this) == DialogResult.OK)
|
||
{
|
||
ContextMenuStrip menuStrip = (ContextMenuStrip)((ToolStripItem)sender).Owner;
|
||
|
||
if (menuStrip.SourceControl is TreeView selectedTree)
|
||
{
|
||
TreeNode selectedNode = selectedTree.SelectedNode;
|
||
|
||
if (selectedNode.Tag is BuilderSynthNode synthNode)
|
||
{
|
||
if (setReferenceForm.SelectedNode == null)
|
||
{
|
||
synthNode.SoundElementReference = string.Empty;
|
||
}
|
||
|
||
else
|
||
{
|
||
synthNode.SoundElementReference = setReferenceForm.SelectedNode.FullPath;
|
||
|
||
if (Settings.RenameToSoundElement)
|
||
{
|
||
RenameNode(selectedNode, setReferenceForm.SelectedNode.Name);
|
||
}
|
||
}
|
||
}
|
||
|
||
saved = false;
|
||
propertyGrid.Refresh();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
private void SetAudio(object sender, EventArgs e)
|
||
{
|
||
ContextMenuStrip menuStrip = (ContextMenuStrip)((ToolStripItem)sender).Owner;
|
||
|
||
if (menuStrip.SourceControl is TreeView selectedTree)
|
||
{
|
||
TreeNode selectedNode = selectedTree.SelectedNode;
|
||
|
||
if (selectedNode.Tag is BuilderSoundElementNode soundElementNode)
|
||
{
|
||
string intro = soundElementNode.Intro;
|
||
if (!string.IsNullOrEmpty(intro))
|
||
{
|
||
intro = Path.Combine(project.AudioDirectory.FullName, intro);
|
||
}
|
||
|
||
string loop = soundElementNode.Loop;
|
||
if (!string.IsNullOrEmpty(loop))
|
||
{
|
||
loop = Path.Combine(project.AudioDirectory.FullName, loop);
|
||
}
|
||
|
||
using (SetAudioForm setAudioForm = new SetAudioForm(intro, loop))
|
||
{
|
||
if (setAudioForm.ShowDialog(this) == DialogResult.OK)
|
||
{
|
||
uint sampleRate = soundElementNode.SampleRate;
|
||
byte channelCount = soundElementNode.ChannelCount;
|
||
|
||
uint introSampleCount = 0;
|
||
soundElementNode.Intro = project.AddAudio(setAudioForm.Intro);
|
||
if (!string.IsNullOrEmpty(setAudioForm.Intro))
|
||
{
|
||
ReadAdx(setAudioForm.Intro, out sampleRate, out channelCount, out introSampleCount);
|
||
}
|
||
|
||
uint loopSampleCount = 0;
|
||
soundElementNode.Loop = project.AddAudio(setAudioForm.Loop);
|
||
if (!string.IsNullOrEmpty(setAudioForm.Loop))
|
||
{
|
||
ReadAdx(setAudioForm.Loop, out sampleRate, out channelCount, out loopSampleCount);
|
||
}
|
||
|
||
soundElementNode.SampleRate = sampleRate;
|
||
soundElementNode.ChannelCount = channelCount;
|
||
soundElementNode.SampleCount = introSampleCount + loopSampleCount;
|
||
propertyGrid.Refresh();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
public void ReadAdx(string path, out uint sampleRate, out byte channelCount, out uint 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)
|
||
{
|
||
ContextMenuStrip menuStrip = (ContextMenuStrip)((ToolStripItem)sender).Owner;
|
||
|
||
if (menuStrip.SourceControl is TreeView selectedTree)
|
||
{
|
||
TreeNode selectedNode = selectedTree.SelectedNode;
|
||
|
||
if (selectedNode.Tag == null)
|
||
{
|
||
CreateSoundNode(selectedNode.Nodes, selectedNode);
|
||
}
|
||
}
|
||
}
|
||
|
||
private void CreateSound(object sender, EventArgs e)
|
||
{
|
||
ContextMenuStrip menuStrip = (ContextMenuStrip)((ToolStripItem)sender).Owner;
|
||
|
||
if (menuStrip.SourceControl is TreeView selectedTree)
|
||
{
|
||
CreateSoundNode(selectedTree.Nodes, null);
|
||
}
|
||
}
|
||
|
||
private int GetByteCountFromMiliseconds(int miliseconds, int sampleRate, int channelCount, int bitsPerSample)
|
||
{
|
||
return (int)(miliseconds * sampleRate / 1000.0) * channelCount * bitsPerSample / 8;
|
||
}
|
||
|
||
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))
|
||
{
|
||
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))
|
||
{
|
||
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))
|
||
{
|
||
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)
|
||
{
|
||
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 delayTime)
|
||
{
|
||
AddSoundElementSound((BuilderSoundElementNode)soundElementTreeNode.Tag, volume, pitch, delayTime);
|
||
}
|
||
|
||
private double GetSecondsFromSampleCount(int sampleCount, int sampleRate)
|
||
{
|
||
return sampleCount / (double)sampleRate;
|
||
}
|
||
|
||
private void GetTheBiggestSampleCount(TreeNode synthTreeNode, ref int sampleCount)
|
||
{
|
||
if (synthTreeNode.Tag is BuilderSynthNode synthNode)
|
||
{
|
||
if (synthNode.Type == BuilderSynthType.Single && !string.IsNullOrEmpty(synthNode.SoundElementReference))
|
||
{
|
||
BuilderSoundElementNode soundElementNode = (BuilderSoundElementNode)soundElementTree.FindNodeByFullPath(synthNode.SoundElementReference).Tag;
|
||
|
||
// We want the loop to be at least 10 seconds
|
||
int soundElementSampleCount = (int)soundElementNode.SampleCount;
|
||
|
||
while (GetSecondsFromSampleCount(soundElementSampleCount, (int)soundElementNode.SampleRate) < 10.0)
|
||
{
|
||
soundElementSampleCount *= 2;
|
||
}
|
||
|
||
if (soundElementSampleCount > sampleCount)
|
||
{
|
||
sampleCount = soundElementSampleCount;
|
||
}
|
||
}
|
||
}
|
||
|
||
foreach (TreeNode childNode in synthTreeNode.Nodes)
|
||
{
|
||
GetTheBiggestSampleCount(childNode, ref sampleCount);
|
||
}
|
||
}
|
||
|
||
private double GetAbsolutePitch(TreeNode synthTreeNode)
|
||
{
|
||
double pitch = 0;
|
||
|
||
while (synthTreeNode != null)
|
||
{
|
||
if (synthTreeNode.Tag is BuilderSynthNode synthNode)
|
||
{
|
||
pitch += synthNode.Pitch;
|
||
}
|
||
|
||
synthTreeNode = synthTreeNode.Parent;
|
||
}
|
||
|
||
return pitch / 1500.0;
|
||
}
|
||
|
||
private double GetAbsoluteVolume(TreeNode synthTreeNode)
|
||
{
|
||
double volume = 1000;
|
||
|
||
while (synthTreeNode != null)
|
||
{
|
||
if (synthTreeNode.Tag is BuilderSynthNode synthNode)
|
||
{
|
||
volume = (volume * synthNode.Volume) / 1000.0;
|
||
}
|
||
|
||
synthTreeNode = synthTreeNode.Parent;
|
||
}
|
||
|
||
return volume / 1000.0;
|
||
}
|
||
|
||
private int GetAbsoluteDelayTime(TreeNode synthTreeNode)
|
||
{
|
||
int delayTime = 0;
|
||
|
||
while (synthTreeNode != null)
|
||
{
|
||
if (synthTreeNode.Tag is BuilderSynthNode synthNode)
|
||
{
|
||
delayTime += (int)synthNode.DelayTime;
|
||
}
|
||
|
||
synthTreeNode = synthTreeNode.Parent;
|
||
}
|
||
|
||
return delayTime;
|
||
}
|
||
|
||
private void AddSynthSound(TreeNode synthTreeNode)
|
||
{
|
||
BuilderSynthNode synthNode = (BuilderSynthNode)synthTreeNode.Tag;
|
||
|
||
if (synthNode.Type == BuilderSynthType.WithChildren)
|
||
{
|
||
if (synthNode.PlaybackType == BuilderSynthPlaybackType.RandomNoRepeat || synthNode.PlaybackType == BuilderSynthPlaybackType.Random)
|
||
{
|
||
TreeNode childNode = synthTreeNode.Nodes[synthNode.RandomChildNode];
|
||
BuilderSynthNode childSynthNode = (BuilderSynthNode)childNode.Tag;
|
||
|
||
if (childSynthNode.Type == BuilderSynthType.Single && !string.IsNullOrEmpty(childSynthNode.SoundElementReference) && childSynthNode.PlayThisTurn)
|
||
{
|
||
AddSoundElementSound(soundElementTree.FindNodeByFullPath(childSynthNode.SoundElementReference), GetAbsoluteVolume(childNode), GetAbsolutePitch(childNode), GetAbsoluteDelayTime(childNode));
|
||
}
|
||
|
||
else if (childSynthNode.Type == BuilderSynthType.WithChildren)
|
||
{
|
||
AddSynthSound(childNode);
|
||
}
|
||
}
|
||
|
||
else if (synthNode.PlaybackType == BuilderSynthPlaybackType.Sequential)
|
||
{
|
||
TreeNode childNode = synthTreeNode.Nodes[synthNode.NextChildNode];
|
||
BuilderSynthNode childSynthNode = (BuilderSynthNode)childNode.Tag;
|
||
|
||
if (childSynthNode.Type == BuilderSynthType.Single && !string.IsNullOrEmpty(childSynthNode.SoundElementReference) && childSynthNode.PlayThisTurn)
|
||
{
|
||
AddSoundElementSound(soundElementTree.FindNodeByFullPath(childSynthNode.SoundElementReference), GetAbsoluteVolume(childNode), GetAbsolutePitch(childNode), GetAbsoluteDelayTime(childNode));
|
||
}
|
||
|
||
else if (childSynthNode.Type == BuilderSynthType.WithChildren)
|
||
{
|
||
AddSynthSound(childNode);
|
||
}
|
||
}
|
||
|
||
else
|
||
{
|
||
foreach (TreeNode childNode in synthTreeNode.Nodes)
|
||
{
|
||
BuilderSynthNode childSynthNode = (BuilderSynthNode)childNode.Tag;
|
||
|
||
if (childSynthNode.Type == BuilderSynthType.Single && !string.IsNullOrEmpty(childSynthNode.SoundElementReference) && childSynthNode.PlayThisTurn)
|
||
{
|
||
AddSoundElementSound(soundElementTree.FindNodeByFullPath(childSynthNode.SoundElementReference), GetAbsoluteVolume(childNode), GetAbsolutePitch(childNode), GetAbsoluteDelayTime(childNode));
|
||
}
|
||
|
||
else if (childSynthNode.Type == BuilderSynthType.WithChildren)
|
||
{
|
||
AddSynthSound(childNode);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
else if (synthNode.Type == BuilderSynthType.Single)
|
||
{
|
||
if (!string.IsNullOrEmpty(synthNode.SoundElementReference) && synthNode.PlayThisTurn)
|
||
{
|
||
AddSoundElementSound(soundElementTree.FindNodeByFullPath(synthNode.SoundElementReference), synthNode.Volume / 1000.0, synthNode.Pitch / 1500.0, (int)synthNode.DelayTime);
|
||
}
|
||
}
|
||
}
|
||
|
||
private int GetTheBiggestSampleCount(TreeNode synthNode)
|
||
{
|
||
int sampleCount = -1;
|
||
GetTheBiggestSampleCount(synthNode, ref sampleCount);
|
||
|
||
return sampleCount;
|
||
}
|
||
|
||
private void PlaySound(object sender, EventArgs e)
|
||
{
|
||
StopSound(sender, e);
|
||
|
||
if (cueTree.Focused && cueTree.SelectedNode != null && cueTree.SelectedNode.Tag is BuilderCueNode cueNode)
|
||
{
|
||
if (!string.IsNullOrEmpty(cueNode.SynthReference))
|
||
{
|
||
TreeNode synthNode = synthTree.FindNodeByFullPath(cueNode.SynthReference);
|
||
AddSynthSound(synthNode);
|
||
}
|
||
}
|
||
|
||
else if (soundElementTree.Focused && soundElementTree.SelectedNode != null && soundElementTree.SelectedNode.Tag is BuilderSoundElementNode)
|
||
{
|
||
AddSoundElementSound(soundElementTree.SelectedNode, 1, 0, 0);
|
||
}
|
||
|
||
else if (synthTree.Focused && synthTree.SelectedNode != null && synthTree.SelectedNode.Tag is BuilderSynthNode)
|
||
{
|
||
AddSynthSound(synthTree.SelectedNode);
|
||
}
|
||
|
||
sounds.ForEach(sound => sound.Play());
|
||
}
|
||
|
||
private void StopSound(object sender, EventArgs e)
|
||
{
|
||
sounds.ForEach(sound =>
|
||
{
|
||
sound.Stop();
|
||
sound.Dispose();
|
||
});
|
||
|
||
sounds.Clear();
|
||
}
|
||
|
||
private TreeNode CloneNode(TreeNode treeNode)
|
||
{
|
||
TreeNode clonedNode = (TreeNode)treeNode.Clone();
|
||
CloneTag(clonedNode);
|
||
|
||
return clonedNode;
|
||
}
|
||
|
||
private void CloneTag(TreeNode treeNode)
|
||
{
|
||
if (treeNode.Tag != null && treeNode.Tag is ICloneable clonable)
|
||
{
|
||
treeNode.Tag = clonable.Clone();
|
||
}
|
||
|
||
foreach (TreeNode childNode in treeNode.Nodes)
|
||
{
|
||
CloneTag(childNode);
|
||
}
|
||
}
|
||
|
||
private void CopyNode(TreeNode treeNode)
|
||
{
|
||
treeViewOfCopiedNode = treeNode.TreeView;
|
||
copiedNode = CloneNode(treeNode);
|
||
}
|
||
|
||
private void CopyNode(object sender, EventArgs e)
|
||
{
|
||
ContextMenuStrip menuStrip = (ContextMenuStrip)((ToolStripItem)sender).Owner;
|
||
|
||
if (menuStrip.SourceControl is TreeView selectedTree)
|
||
{
|
||
CopyNode(selectedTree.SelectedNode);
|
||
}
|
||
}
|
||
|
||
private void AddToProject(TreeNode treeNode)
|
||
{
|
||
if (treeNode.Tag is BuilderCueNode cueNode)
|
||
{
|
||
// Do checks
|
||
if (!string.IsNullOrEmpty(cueNode.SynthReference) && synthTree.FindNodeByFullPath(cueNode.SynthReference) == null)
|
||
{
|
||
cueNode.SynthReference = string.Empty;
|
||
}
|
||
|
||
project.CueNodes.Add(cueNode);
|
||
}
|
||
|
||
else if (treeNode.Tag is BuilderSynthNode synthNode)
|
||
{
|
||
if (!string.IsNullOrEmpty(synthNode.SoundElementReference) && soundElementTree.FindNodeByFullPath(synthNode.SoundElementReference) == null)
|
||
{
|
||
synthNode.SoundElementReference = string.Empty;
|
||
}
|
||
|
||
if (!string.IsNullOrEmpty(synthNode.AisacReference) && aisacTree.FindNodeByFullPath(synthNode.AisacReference) == null)
|
||
{
|
||
synthNode.AisacReference = string.Empty;
|
||
}
|
||
|
||
if (!string.IsNullOrEmpty(synthNode.VoiceLimitGroupReference) && !voiceLimitGroupTree.Nodes.ContainsKey(synthNode.VoiceLimitGroupReference))
|
||
{
|
||
synthNode.VoiceLimitGroupReference = string.Empty;
|
||
}
|
||
|
||
project.SynthNodes.Add(synthNode);
|
||
}
|
||
|
||
if (treeNode.Tag is BuilderSoundElementNode soundElementNode)
|
||
{
|
||
if (!string.IsNullOrEmpty(soundElementNode.Intro) && !File.Exists(project.GetFullAudioPath(soundElementNode.Intro)))
|
||
{
|
||
soundElementNode.Intro = string.Empty;
|
||
}
|
||
|
||
if (!string.IsNullOrEmpty(soundElementNode.Loop) && !File.Exists(project.GetFullAudioPath(soundElementNode.Loop)))
|
||
{
|
||
soundElementNode.Loop = string.Empty;
|
||
}
|
||
|
||
project.SoundElementNodes.Add(soundElementNode);
|
||
}
|
||
|
||
if (treeNode.Tag is BuilderAisacNode aisacNode)
|
||
{
|
||
project.AisacNodes.Add(aisacNode);
|
||
}
|
||
|
||
if (treeNode.Tag is BuilderVoiceLimitGroupNode voiceLimitGroupNode)
|
||
{
|
||
project.VoiceLimitGroupNodes.Add(voiceLimitGroupNode);
|
||
}
|
||
}
|
||
|
||
private void PasteAsChildNode(TreeNode parent, int nodeIndex = -1)
|
||
{
|
||
saved = false;
|
||
|
||
TreeNode nodeToPaste = CloneNode(copiedNode);
|
||
|
||
// Look for any duplicates
|
||
int index = -1;
|
||
string name = nodeToPaste.Name;
|
||
|
||
while (parent.Nodes.ContainsKey(nodeToPaste.Name))
|
||
{
|
||
nodeToPaste.Name = $"{name}_Copy{++index}";
|
||
}
|
||
|
||
nodeToPaste.Text = nodeToPaste.Name;
|
||
|
||
// paste it now
|
||
if (nodeIndex == -1)
|
||
{
|
||
parent.Nodes.Add(nodeToPaste);
|
||
}
|
||
|
||
else
|
||
{
|
||
parent.Nodes.Insert(nodeIndex, nodeToPaste);
|
||
}
|
||
|
||
// Update the CSB node and its children (will prevent some issues)
|
||
UpdateNodeNoRename(nodeToPaste);
|
||
|
||
// fix node if the tree is synthTree, and the nodes are synth nodes
|
||
if (parent.TreeView == synthTree && parent.Tag is BuilderSynthNode synthNode && nodeToPaste.Tag is BuilderSynthNode copiedSynthNode)
|
||
{
|
||
if (synthNode.Type == BuilderSynthType.WithChildren)
|
||
{
|
||
// add the new node to track's children
|
||
synthNode.Children.Add(copiedSynthNode.Name);
|
||
}
|
||
}
|
||
|
||
AddToProject(nodeToPaste);
|
||
|
||
nodeToPaste.TreeView.SelectedNode = nodeToPaste;
|
||
nodeToPaste.EnsureVisible();
|
||
}
|
||
|
||
private void PasteNode(object sender, EventArgs e)
|
||
{
|
||
ContextMenuStrip menuStrip = (ContextMenuStrip)((ToolStripItem)sender).Owner;
|
||
|
||
if (menuStrip.SourceControl is TreeView selectedTree)
|
||
{
|
||
TreeNode selectedNode = selectedTree.SelectedNode;
|
||
|
||
if (selectedTree == treeViewOfCopiedNode)
|
||
{
|
||
// Parent is a CSB node but the copied object is a folder? abort.
|
||
if (selectedNode.Tag != null && copiedNode.Tag == null)
|
||
{
|
||
return;
|
||
}
|
||
|
||
PasteAsChildNode(selectedNode);
|
||
}
|
||
}
|
||
}
|
||
|
||
private void PasteNode(int nodeIndex = -1)
|
||
{
|
||
saved = false;
|
||
|
||
TreeNode nodeToPaste = CloneNode(copiedNode);
|
||
|
||
// check if it's cue and fix duplicate identifier if needed
|
||
if (nodeToPaste.Tag is BuilderCueNode cueNode)
|
||
{
|
||
while (project.CueNodes.Exists(cue => cue.Identifier == cueNode.Identifier))
|
||
{
|
||
cueNode.Identifier++;
|
||
}
|
||
}
|
||
|
||
// paste
|
||
if (treeViewOfCopiedNode.SelectedNode != null && treeViewOfCopiedNode.SelectedNode.Parent != null)
|
||
{
|
||
// Look for any duplicates
|
||
int index = -1;
|
||
string name = nodeToPaste.Name;
|
||
|
||
while (treeViewOfCopiedNode.SelectedNode.Parent.Nodes.ContainsKey(nodeToPaste.Name))
|
||
{
|
||
nodeToPaste.Name = $"{name}_Copy{++index}";
|
||
}
|
||
|
||
nodeToPaste.Text = nodeToPaste.Name;
|
||
|
||
if (nodeIndex == -1)
|
||
{
|
||
treeViewOfCopiedNode.SelectedNode.Parent.Nodes.Add(nodeToPaste);
|
||
}
|
||
|
||
else
|
||
{
|
||
treeViewOfCopiedNode.SelectedNode.Parent.Nodes.Insert(nodeIndex, nodeToPaste);
|
||
}
|
||
}
|
||
|
||
else
|
||
{
|
||
// Look for any duplicates
|
||
int index = -1;
|
||
string name = nodeToPaste.Name;
|
||
|
||
while (treeViewOfCopiedNode.Nodes.ContainsKey(nodeToPaste.Name))
|
||
{
|
||
nodeToPaste.Name = $"{name}_Copy{++index}";
|
||
}
|
||
|
||
nodeToPaste.Text = nodeToPaste.Name;
|
||
|
||
if (nodeIndex == -1)
|
||
{
|
||
treeViewOfCopiedNode.Nodes.Add(nodeToPaste);
|
||
}
|
||
|
||
else
|
||
{
|
||
treeViewOfCopiedNode.Nodes.Insert(nodeIndex, nodeToPaste);
|
||
}
|
||
}
|
||
|
||
// update the CSB node and its children
|
||
UpdateNodeNoRename(nodeToPaste);
|
||
AddToProject(nodeToPaste);
|
||
|
||
nodeToPaste.TreeView.SelectedNode = nodeToPaste;
|
||
nodeToPaste.EnsureVisible();
|
||
}
|
||
|
||
private void PasteNodeOnTree(object sender, EventArgs e)
|
||
{
|
||
ContextMenuStrip menuStrip = (ContextMenuStrip)((ToolStripItem)sender).Owner;
|
||
|
||
if (menuStrip.SourceControl is TreeView selectedTree)
|
||
{
|
||
if (selectedTree == treeViewOfCopiedNode)
|
||
{
|
||
PasteNode();
|
||
}
|
||
}
|
||
}
|
||
|
||
private void PasteAndInsertNode(object sender, EventArgs e)
|
||
{
|
||
ContextMenuStrip menuStrip = (ContextMenuStrip)((ToolStripItem)sender).Owner;
|
||
|
||
if (menuStrip.SourceControl is TreeView selectedTree)
|
||
{
|
||
TreeNode selectedNode = selectedTree.SelectedNode;
|
||
|
||
if (selectedTree == treeViewOfCopiedNode)
|
||
{
|
||
PasteNode(selectedNode.Index + 1);
|
||
}
|
||
}
|
||
}
|
||
|
||
private void ShowAbout(object sender, EventArgs e)
|
||
{
|
||
MessageBox.Show($"{Program.ApplicationTitle} by Skyth (blueskythlikesclouds)", "CSB Builder");
|
||
}
|
||
|
||
private void CreateChildTrackNode(object sender, EventArgs e)
|
||
{
|
||
ContextMenuStrip menuStrip = (ContextMenuStrip)((ToolStripItem)sender).Owner;
|
||
|
||
if (menuStrip.SourceControl is TreeView selectedTree)
|
||
{
|
||
TreeNode selectedNode = selectedTree.SelectedNode;
|
||
|
||
if (selectedTree == synthTree)
|
||
{
|
||
CreateSynthNode(selectedNode.Nodes, selectedNode);
|
||
}
|
||
}
|
||
}
|
||
|
||
private void CreateAndInsertNode(object sender, EventArgs e)
|
||
{
|
||
ContextMenuStrip menuStrip = (ContextMenuStrip)((ToolStripItem)sender).Owner;
|
||
|
||
if (menuStrip.SourceControl is TreeView selectedTree)
|
||
{
|
||
TreeNode selectedNode = selectedTree.SelectedNode;
|
||
|
||
if (selectedTree == cueTree)
|
||
{
|
||
CreateCueNode(selectedTree.Nodes, null, selectedNode.Index + 1);
|
||
}
|
||
|
||
else if (selectedTree == synthTree)
|
||
{
|
||
if (selectedNode.Tag is BuilderSynthNode synthNode && synthNode.Type == BuilderSynthType.WithChildren)
|
||
{
|
||
CreateSoundNode(selectedNode.Nodes, selectedNode, selectedNode.Index + 1);
|
||
}
|
||
|
||
else
|
||
{
|
||
CreateSynthNode(selectedNode.Nodes, selectedNode, selectedNode.Index + 1);
|
||
}
|
||
}
|
||
|
||
else if (selectedTree == soundElementTree)
|
||
{
|
||
CreateSoundElementNode(selectedNode.Parent != null ? selectedNode.Parent.Nodes : selectedTree.Nodes, selectedNode, selectedNode.Index + 1);
|
||
}
|
||
|
||
else if (selectedTree == aisacTree)
|
||
{
|
||
CreateAisacNode(selectedNode.Nodes, selectedNode, selectedNode.Index + 1);
|
||
}
|
||
|
||
else if (selectedTree == voiceLimitGroupTree)
|
||
{
|
||
CreateVoiceLimitGroupNode(selectedTree.Nodes, null, selectedNode.Index + 1);
|
||
}
|
||
}
|
||
}
|
||
|
||
private void CreateAndInsertSoundNode(object sender, EventArgs e)
|
||
{
|
||
ContextMenuStrip menuStrip = (ContextMenuStrip)((ToolStripItem)sender).Owner;
|
||
|
||
if (menuStrip.SourceControl is TreeView selectedTree)
|
||
{
|
||
TreeNode selectedNode = selectedTree.SelectedNode;
|
||
|
||
if (selectedNode.Tag is BuilderSynthNode)
|
||
{
|
||
if (selectedNode.Parent == null)
|
||
{
|
||
CreateSoundNode(synthTree.Nodes, null, selectedNode.Index + 1);
|
||
}
|
||
|
||
else
|
||
{
|
||
CreateSoundNode(selectedNode.Parent.Nodes, selectedNode.Parent, selectedNode.Index + 1);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
private void LoadTemplate(object sender, EventArgs e)
|
||
{
|
||
ContextMenuStrip menuStrip = (ContextMenuStrip)((ToolStripItem)sender).Owner;
|
||
|
||
if (menuStrip.SourceControl is TreeView selectedTree)
|
||
{
|
||
TreeNode selectedNode = selectedTree.SelectedNode;
|
||
|
||
if (selectedTree == aisacTree)
|
||
{
|
||
using (OpenFileDialog openAisacTemplate = new OpenFileDialog()
|
||
{
|
||
Title = "Load AISAC Template",
|
||
Filter = "XML Files|*.xml",
|
||
DefaultExt = "xml",
|
||
FileName = selectedNode != null ? selectedNode.Name : string.Empty,
|
||
})
|
||
{
|
||
if (openAisacTemplate.ShowDialog() == DialogResult.OK)
|
||
{
|
||
XmlSerializer aisacSerializer = new XmlSerializer(typeof(BuilderAisacNode));
|
||
|
||
try
|
||
{
|
||
using (Stream source = File.OpenRead(openAisacTemplate.FileName))
|
||
{
|
||
BuilderAisacNode aisacNode = (BuilderAisacNode)aisacSerializer.Deserialize(source);
|
||
TreeNode aisacTreeNode = null;
|
||
|
||
// folder
|
||
if (selectedNode != null && selectedNode.Tag == null)
|
||
{
|
||
aisacTreeNode = CreateAisacNode(selectedNode.Nodes, selectedNode, -1, aisacNode);
|
||
}
|
||
|
||
// aisac
|
||
else if (selectedNode != null && selectedNode.Tag is BuilderAisacNode)
|
||
{
|
||
project.AisacNodes[project.AisacNodes.IndexOf((BuilderAisacNode)selectedNode.Tag)] = aisacNode;
|
||
|
||
aisacNode.Name = selectedNode.FullPath;
|
||
selectedNode.Tag = aisacNode;
|
||
selectedTree.SelectedNode = selectedNode;
|
||
}
|
||
|
||
// nothing, create a new aisac
|
||
else if (selectedNode == null)
|
||
{
|
||
aisacTreeNode = CreateAisacNode(aisacTree.Nodes, null, -1, aisacNode);
|
||
}
|
||
|
||
// fix the current aisac if it was imported
|
||
if (aisacTreeNode != null)
|
||
{
|
||
if (!string.IsNullOrEmpty(aisacNode.Name))
|
||
{
|
||
// duplicate? fix it really quick
|
||
string name = Path.GetFileName(aisacNode.Name);
|
||
string uniqueName = name;
|
||
|
||
TreeNodeCollection collection = aisacTreeNode.Parent != null ? aisacTreeNode.Parent.Nodes : aisacTree.Nodes;
|
||
|
||
int index = -1;
|
||
while (collection.ContainsKey(uniqueName))
|
||
{
|
||
uniqueName = $"{name}_{++index}";
|
||
}
|
||
|
||
aisacTreeNode.Name = uniqueName;
|
||
aisacTreeNode.Text = aisacTreeNode.Name;
|
||
}
|
||
|
||
aisacNode.Name = aisacTreeNode.FullPath;
|
||
aisacTreeNode.Tag = aisacNode;
|
||
|
||
selectedTree.SelectedNode = aisacTreeNode;
|
||
aisacTreeNode.EnsureVisible();
|
||
}
|
||
}
|
||
}
|
||
|
||
catch
|
||
{
|
||
MessageBox.Show("The template file is invalid.", "CSB Builder", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
private void SaveTemplate(object sender, EventArgs e)
|
||
{
|
||
ContextMenuStrip menuStrip = (ContextMenuStrip)((ToolStripItem)sender).Owner;
|
||
|
||
if (menuStrip.SourceControl is TreeView selectedTree)
|
||
{
|
||
TreeNode selectedNode = selectedTree.SelectedNode;
|
||
|
||
if (selectedTree == aisacTree)
|
||
{
|
||
using (SaveFileDialog saveAisacTemplate = new SaveFileDialog()
|
||
{
|
||
Title = "Save AISAC Template",
|
||
Filter = "XML Files|*.xml",
|
||
DefaultExt = "xml",
|
||
FileName = selectedNode.Name,
|
||
})
|
||
{
|
||
if (saveAisacTemplate.ShowDialog() == DialogResult.OK)
|
||
{
|
||
if (selectedNode.Tag is BuilderAisacNode)
|
||
{
|
||
XmlSerializer aisacSerializer = new XmlSerializer(typeof(BuilderAisacNode));
|
||
|
||
using (Stream destination = File.Create(saveAisacTemplate.FileName))
|
||
{
|
||
aisacSerializer.Serialize(destination, selectedNode.Tag);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
private void OpenSettings(object sender, EventArgs e)
|
||
{
|
||
using (SettingsForm settings = new SettingsForm())
|
||
{
|
||
settings.ShowDialog(this);
|
||
}
|
||
}
|
||
|
||
private void convertADXsToWAVToolStripMenuItem_Click(object sender, EventArgs e)
|
||
{
|
||
using (OpenFileDialog openFileDialog = new OpenFileDialog
|
||
{
|
||
Title = "Convert 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)
|
||
using (WaveFileWriter writer = new WaveFileWriter(
|
||
Path.Combine(
|
||
Path.GetDirectoryName(saveFileDialog.FileName),
|
||
Path.GetFileNameWithoutExtension(fileName) + ".wav"),
|
||
reader.WaveFormat))
|
||
{
|
||
if (reader.LoopFlag)
|
||
{
|
||
// 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);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
private void extractAAXToFolderToolStripMenuItem_Click(object sender, EventArgs e)
|
||
{
|
||
using (OpenFileDialog openFileDialog = new OpenFileDialog
|
||
{
|
||
Title = "Extract AAX Files",
|
||
FileName = "Select AAX files you want to extract and press Open",
|
||
Filter = "AAX Files|*.aax",
|
||
DefaultExt = "aax",
|
||
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)
|
||
{
|
||
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();
|
||
aaxArchive.Load(fileName, Settings.BufferSize);
|
||
|
||
foreach (CriAaxEntry entry in aaxArchive)
|
||
{
|
||
using (Stream source = File.OpenRead(fileName))
|
||
{
|
||
extractor.Add(fileName, Path.Combine(
|
||
Path.GetDirectoryName(saveFileDialog.FileName),
|
||
$"{Path.GetFileNameWithoutExtension(fileName)}_{entry.Flag}{aaxArchive.GetModeExtension()}"),
|
||
entry.Position,
|
||
entry.Length);
|
||
}
|
||
}
|
||
}
|
||
|
||
extractor.Run();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
private void packFolderToAAXToolStripMenuItem_Click(object sender, EventArgs e)
|
||
{
|
||
using (OpenFileDialog openFileDialog = new OpenFileDialog
|
||
{
|
||
Title = "Pack ADX Files",
|
||
FileName = "Select ADX files you want to pack and press Open",
|
||
Filter = "All Files|*.adx;*.wav|ADX Files|*.adx|WAV Files|*.wav",
|
||
Multiselect = true,
|
||
})
|
||
{
|
||
string[] files = null;
|
||
DialogResult dialogResult;
|
||
|
||
while ((dialogResult = openFileDialog.ShowDialog(this)) == DialogResult.OK)
|
||
{
|
||
if (openFileDialog.FileNames.Length > 2)
|
||
{
|
||
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;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (dialogResult == DialogResult.OK)
|
||
{
|
||
using (SaveFileDialog saveFileDialog = new SaveFileDialog
|
||
{
|
||
Title = "Output File",
|
||
FileName = $"{Path.GetFileNameWithoutExtension(files[0])}.aax",
|
||
Filter = "AAX Files|*.aax",
|
||
DefaultExt = "aax",
|
||
})
|
||
{
|
||
if (saveFileDialog.ShowDialog(this) == DialogResult.OK)
|
||
{
|
||
CriAaxArchive archive = new CriAaxArchive();
|
||
archive.SetModeFromExtension(files[0]);
|
||
|
||
for (int i = 0; i < files.Length; i++)
|
||
{
|
||
archive.Add(new CriAaxEntry { FilePath = new FileInfo(files[i]), Flag = (CriAaxEntryFlag)i });
|
||
}
|
||
|
||
archive.Save(saveFileDialog.FileName);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
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);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|