1
0
mirror of synced 2024-11-14 08:57:34 +01:00

first commit

This commit is contained in:
NotImplementedLife 2023-07-17 11:20:00 +03:00
commit 1ff7354141
66 changed files with 6954 additions and 0 deletions

206
Controls/FolderPicker.cs Normal file
View File

@ -0,0 +1,206 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices.ComTypes;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace TaikoSoundEditor
{
public class FolderPicker
{
public virtual string ResultPath { get; protected set; }
public virtual string ResultName { get; protected set; }
public virtual string InputPath { get; set; }
public virtual bool ForceFileSystem { get; set; }
public virtual string Title { get; set; }
public virtual string OkButtonLabel { get; set; }
public virtual string FileNameLabel { get; set; }
protected virtual int SetOptions(int options)
{
if (ForceFileSystem)
{
options |= (int)FOS.FOS_FORCEFILESYSTEM;
}
return options;
}
public bool? ShowDialog()
{
return ShowDialog(IntPtr.Zero);
}
public virtual bool? ShowDialog(IntPtr owner, bool throwOnError = false)
{
var dialog = (IFileOpenDialog)new FileOpenDialog();
if (!string.IsNullOrEmpty(InputPath))
{
if (CheckHr(SHCreateItemFromParsingName(InputPath, null, typeof(IShellItem).GUID, out var item), throwOnError) != 0)
return null;
dialog.SetFolder(item);
}
var options = FOS.FOS_PICKFOLDERS;
options = (FOS)SetOptions((int)options);
dialog.SetOptions(options);
if (Title != null)
{
dialog.SetTitle(Title);
}
if (OkButtonLabel != null)
{
dialog.SetOkButtonLabel(OkButtonLabel);
}
if (FileNameLabel != null)
{
dialog.SetFileName(FileNameLabel);
}
if (owner == IntPtr.Zero)
{
owner = Process.GetCurrentProcess().MainWindowHandle;
if (owner == IntPtr.Zero)
{
owner = GetDesktopWindow();
}
}
var hr = dialog.Show(owner);
if (hr == ERROR_CANCELLED)
return null;
if (CheckHr(hr, throwOnError) != 0)
return null;
if (CheckHr(dialog.GetResult(out var result), throwOnError) != 0)
return null;
if (CheckHr(result.GetDisplayName(SIGDN.SIGDN_DESKTOPABSOLUTEPARSING, out var path), throwOnError) != 0)
return null;
ResultPath = path;
if (CheckHr(result.GetDisplayName(SIGDN.SIGDN_DESKTOPABSOLUTEEDITING, out path), false) == 0)
{
ResultName = path;
}
return true;
}
private static int CheckHr(int hr, bool throwOnError)
{
if (hr != 0)
{
if (throwOnError)
Marshal.ThrowExceptionForHR(hr);
}
return hr;
}
[DllImport("shell32")]
private static extern int SHCreateItemFromParsingName([MarshalAs(UnmanagedType.LPWStr)] string pszPath, IBindCtx pbc, [MarshalAs(UnmanagedType.LPStruct)] Guid riid, out IShellItem ppv);
[DllImport("user32")]
private static extern IntPtr GetDesktopWindow();
#pragma warning disable IDE1006 // Naming Styles
private const int ERROR_CANCELLED = unchecked((int)0x800704C7);
#pragma warning restore IDE1006 // Naming Styles
[ComImport, Guid("DC1C5A9C-E88A-4dde-A5A1-60F82A20AEF7")] // CLSID_FileOpenDialog
private class FileOpenDialog
{
}
[ComImport, Guid("42f85136-db7e-439c-85f1-e4075d135fc8"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
private interface IFileOpenDialog
{
[PreserveSig] int Show(IntPtr parent); // IModalWindow
[PreserveSig] int SetFileTypes(); // not fully defined
[PreserveSig] int SetFileTypeIndex(int iFileType);
[PreserveSig] int GetFileTypeIndex(out int piFileType);
[PreserveSig] int Advise(); // not fully defined
[PreserveSig] int Unadvise();
[PreserveSig] int SetOptions(FOS fos);
[PreserveSig] int GetOptions(out FOS pfos);
[PreserveSig] int SetDefaultFolder(IShellItem psi);
[PreserveSig] int SetFolder(IShellItem psi);
[PreserveSig] int GetFolder(out IShellItem ppsi);
[PreserveSig] int GetCurrentSelection(out IShellItem ppsi);
[PreserveSig] int SetFileName([MarshalAs(UnmanagedType.LPWStr)] string pszName);
[PreserveSig] int GetFileName([MarshalAs(UnmanagedType.LPWStr)] out string pszName);
[PreserveSig] int SetTitle([MarshalAs(UnmanagedType.LPWStr)] string pszTitle);
[PreserveSig] int SetOkButtonLabel([MarshalAs(UnmanagedType.LPWStr)] string pszText);
[PreserveSig] int SetFileNameLabel([MarshalAs(UnmanagedType.LPWStr)] string pszLabel);
[PreserveSig] int GetResult(out IShellItem ppsi);
[PreserveSig] int AddPlace(IShellItem psi, int alignment);
[PreserveSig] int SetDefaultExtension([MarshalAs(UnmanagedType.LPWStr)] string pszDefaultExtension);
[PreserveSig] int Close(int hr);
[PreserveSig] int SetClientGuid(); // not fully defined
[PreserveSig] int ClearClientData();
[PreserveSig] int SetFilter([MarshalAs(UnmanagedType.IUnknown)] object pFilter);
[PreserveSig] int GetResults([MarshalAs(UnmanagedType.IUnknown)] out object ppenum);
[PreserveSig] int GetSelectedItems([MarshalAs(UnmanagedType.IUnknown)] out object ppsai);
}
[ComImport, Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
private interface IShellItem
{
[PreserveSig] int BindToHandler(); // not fully defined
[PreserveSig] int GetParent(); // not fully defined
[PreserveSig] int GetDisplayName(SIGDN sigdnName, [MarshalAs(UnmanagedType.LPWStr)] out string ppszName);
[PreserveSig] int GetAttributes(); // not fully defined
[PreserveSig] int Compare(); // not fully defined
}
#pragma warning disable CA1712 // Do not prefix enum values with type name
private enum SIGDN : uint
{
SIGDN_DESKTOPABSOLUTEEDITING = 0x8004c000,
SIGDN_DESKTOPABSOLUTEPARSING = 0x80028000,
SIGDN_FILESYSPATH = 0x80058000,
SIGDN_NORMALDISPLAY = 0,
SIGDN_PARENTRELATIVE = 0x80080001,
SIGDN_PARENTRELATIVEEDITING = 0x80031001,
SIGDN_PARENTRELATIVEFORADDRESSBAR = 0x8007c001,
SIGDN_PARENTRELATIVEPARSING = 0x80018001,
SIGDN_URL = 0x80068000
}
[Flags]
private enum FOS
{
FOS_OVERWRITEPROMPT = 0x2,
FOS_STRICTFILETYPES = 0x4,
FOS_NOCHANGEDIR = 0x8,
FOS_PICKFOLDERS = 0x20,
FOS_FORCEFILESYSTEM = 0x40,
FOS_ALLNONSTORAGEITEMS = 0x80,
FOS_NOVALIDATE = 0x100,
FOS_ALLOWMULTISELECT = 0x200,
FOS_PATHMUSTEXIST = 0x800,
FOS_FILEMUSTEXIST = 0x1000,
FOS_CREATEPROMPT = 0x2000,
FOS_SHAREAWARE = 0x4000,
FOS_NOREADONLYRETURN = 0x8000,
FOS_NOTESTFILECREATE = 0x10000,
FOS_HIDEMRUPLACES = 0x20000,
FOS_HIDEPINNEDPLACES = 0x40000,
FOS_NODEREFERENCELINKS = 0x100000,
FOS_OKBUTTONNEEDSINTERACTION = 0x200000,
FOS_DONTADDTORECENT = 0x2000000,
FOS_FORCESHOWHIDDEN = 0x10000000,
FOS_DEFAULTNOMINIMODE = 0x20000000,
FOS_FORCEPREVIEWPANEON = 0x40000000,
FOS_SUPPORTSTREAMABLEITEMS = unchecked((int)0x80000000)
}
#pragma warning restore CA1712 // Do not prefix enum values with type name
}
}

74
Controls/PathSelector.Designer.cs generated Normal file
View File

@ -0,0 +1,74 @@
namespace TaikoSoundEditor
{
partial class PathSelector
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.DisplayBox = new System.Windows.Forms.TextBox();
this.Button = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// DisplayBox
//
this.DisplayBox.Dock = System.Windows.Forms.DockStyle.Fill;
this.DisplayBox.Location = new System.Drawing.Point(0, 0);
this.DisplayBox.Name = "DisplayBox";
this.DisplayBox.Size = new System.Drawing.Size(117, 20);
this.DisplayBox.TabIndex = 2;
//
// Button
//
this.Button.Dock = System.Windows.Forms.DockStyle.Right;
this.Button.FlatAppearance.BorderSize = 0;
this.Button.Font = new System.Drawing.Font("Microsoft Sans Serif", 7F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.Button.Location = new System.Drawing.Point(117, 0);
this.Button.Name = "Button";
this.Button.Size = new System.Drawing.Size(33, 20);
this.Button.TabIndex = 3;
this.Button.Text = "...";
this.Button.UseVisualStyleBackColor = true;
this.Button.Click += new System.EventHandler(this.Button_Click);
//
// PathSelector
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.DisplayBox);
this.Controls.Add(this.Button);
this.Name = "PathSelector";
this.Size = new System.Drawing.Size(150, 20);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.TextBox DisplayBox;
private System.Windows.Forms.Button Button;
}
}

75
Controls/PathSelector.cs Normal file
View File

@ -0,0 +1,75 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace TaikoSoundEditor
{
[DefaultEvent("PathChanged")]
public partial class PathSelector : UserControl
{
public PathSelector()
{
InitializeComponent();
}
protected override void SetBoundsCore(
int x, int y, int width, int height, BoundsSpecified specified)
{
// EDIT: ADD AN EXTRA HEIGHT VALIDATION TO AVOID INITIALIZATION PROBLEMS
// BITWISE 'AND' OPERATION: IF ZERO THEN HEIGHT IS NOT INVOLVED IN THIS OPERATION
if ((specified & BoundsSpecified.Height) == 0 || height == DisplayBox.Height)
{
base.SetBoundsCore(x, y, width, DisplayBox.Height, specified);
Button.Width = 2 * DisplayBox.Height;
}
else
{
return; // RETURN WITHOUT DOING ANY RESIZING
}
}
public bool SelectsFolder { get; set; } = false;
public string Path
{
get => DisplayBox.Text;
set
{
DisplayBox.Text = value;
PathChanged?.Invoke(this, new EventArgs());
}
}
public delegate void OnPathChanged(object sender, EventArgs args);
public event OnPathChanged PathChanged;
public string Filter { get; set; } = "All files(*.*)|*.*";
private void Button_Click(object sender, EventArgs e)
{
if (SelectsFolder)
{
var dialog = new FolderPicker();
dialog.InputPath = DisplayBox.Text;
if (dialog.ShowDialog() == true)
{
Path = dialog.ResultPath;
}
}
else
{
var dialog = new OpenFileDialog();
dialog.Filter = Filter;
if (dialog.ShowDialog() == DialogResult.OK)
{
Path = dialog.FileName;
}
}
}
}
}

120
Controls/PathSelector.resx Normal file
View File

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

52
Data/MusicAttribute.cs Normal file
View File

@ -0,0 +1,52 @@
using System.ComponentModel;
using System.Text.Json.Serialization;
namespace TaikoSoundEditor.Data
{
public class MusicAttribute
{
[ReadOnly(true)]
[JsonPropertyName("id")] public string Id { get; set; } = "ABCDEF";
[ReadOnly(true)]
[JsonPropertyName("uniqueId")] public int UniqueId { get; set; }
[JsonPropertyName("new")] public bool New { get; set; } = false;
[JsonPropertyName("canPlayUra")] public bool CanPlayUra { get; set; } = false;
[JsonPropertyName("doublePlay")] public bool DoublePlay { get; set; } = false;
[JsonPropertyName("tag1")] public string Tag1 { get; set; } = "";
[JsonPropertyName("tag2")] public string Tag2 { get; set; } = "";
[JsonPropertyName("tag3")] public string Tag3 { get; set; } = "";
[JsonPropertyName("tag4")] public string Tag4 { get; set; } = "";
[JsonPropertyName("tag5")] public string Tag5 { get; set; } = "";
[JsonPropertyName("tag6")] public string Tag6 { get; set; } = "";
[JsonPropertyName("tag7")] public string Tag7 { get; set; } = "";
[JsonPropertyName("tag8")] public string Tag8 { get; set; } = "";
[JsonPropertyName("tag9")] public string Tag9 { get; set; } = "";
[JsonPropertyName("tag10")] public string Tag10 { get; set; } = "";
[JsonPropertyName("donBg1p")] public string DonBg1p { get; set; } = "";
[JsonPropertyName("donBg2p")] public string DonBg2p { get; set; } = "";
[JsonPropertyName("dancerDai")] public string DancerDai { get; set; } = "";
[JsonPropertyName("dancer")] public string Dancer { get; set; } = "";
[JsonPropertyName("danceNormalBg")] public string DanceNormalBg { get; set; } = "";
[JsonPropertyName("danceFeverBg")] public string DanceFeverBg { get; set; } = "";
[JsonPropertyName("rendaEffect")] public string RendaEffect { get; set; } = "";
[JsonPropertyName("fever")] public string Fever { get; set; } = "";
[JsonPropertyName("donBg1p1")] public string DonBg1p1 { get; set; }
[JsonPropertyName("donBg2p1")] public string DonBg2p1 { get; set; }
[JsonPropertyName("dancerDai1")] public string DancerDai1 { get; set; }
[JsonPropertyName("dancer1")] public string Dancer1 { get; set; }
[JsonPropertyName("danceNormalBg1")] public string DanceNormalBg1 { get; set; }
[JsonPropertyName("danceFeverBg1")] public string DanceFeverBg1 { get; set; }
[JsonPropertyName("rendaEffect1")] public string RendaEffect1 { get; set; }
[JsonPropertyName("fever1")] public string Fever1 { get; set; }
public MusicAttribute Clone()
{
var props = GetType().GetProperties();
var clone = new MusicAttribute();
foreach(var p in props)
p.SetValue(clone, p.GetValue(this));
return clone;
}
}
}

25
Data/MusicAttributes.cs Normal file
View File

@ -0,0 +1,25 @@
using System.Text.Json.Serialization;
namespace TaikoSoundEditor.Data
{
public class MusicAttributes
{
[JsonPropertyName("items")]
public List<MusicAttribute> Items { get; set; } = new List<MusicAttribute>();
public MusicAttribute GetByUniqueId(int id)
{
return Items.Find(x => x.UniqueId == id);
}
public int GetNewId()
{
return Items.Max(i => i.UniqueId) + 1;
}
public bool IsValidSongId(string id)
{
return !Items.Any(i => i.Id == id);
}
}
}

77
Data/MusicInfo.cs Normal file
View File

@ -0,0 +1,77 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
namespace TaikoSoundEditor.Data
{
internal class MusicInfo
{
[ReadOnly(true)]
[JsonPropertyName("id")] public string Id { get; set; } = "ABCDEF";
[ReadOnly(true)]
[JsonPropertyName("uniqueId")] public int UniqueId { get; set; } =0;
[JsonPropertyName("genreNo")] public int GenreNo { get; set; } =0;
[JsonPropertyName("songFileName")] public string SongFileName { get; set; } = "";
[JsonPropertyName("papamama")] public bool Papamama { get; set; } = false;
[JsonPropertyName("branchEasy")] public bool BranchEasy { get; set; } = false;
[JsonPropertyName("branchNormal")] public bool BranchNormal { get; set; } = false;
[JsonPropertyName("branchHard")] public bool BranchHard { get; set; } = false;
[JsonPropertyName("branchMania")] public bool BranchMania { get; set; } = false;
[JsonPropertyName("branchUra")] public bool BranchUra { get; set; } = false;
[JsonPropertyName("starEasy")] public int StarEasy { get; set; } = 0;
[JsonPropertyName("starNormal")] public int StarNormal { get; set; } = 0;
[JsonPropertyName("starHard")] public int StarHard { get; set; } = 0;
[JsonPropertyName("starMania")] public int StarMania { get; set; } = 0;
[JsonPropertyName("starUra")] public int StarUra { get; set; } = 0;
[JsonPropertyName("shinutiEasy")] public int ShinutiEasy { get; set; } = 0;
[JsonPropertyName("shinutiNormal")] public int ShinutiNormal { get; set; } = 0;
[JsonPropertyName("shinutiHard")] public int ShinutiHard { get; set; } = 0;
[JsonPropertyName("shinutiMania")] public int ShinutiMania { get; set; } = 0;
[JsonPropertyName("shinutiUra")] public int ShinutiUra { get; set; } = 0;
[JsonPropertyName("shinutiEasyDuet")] public int ShinutiEasyDuet { get; set; } = 0;
[JsonPropertyName("shinutiNormalDuet")] public int ShinutiNormalDuet { get; set; } = 0;
[JsonPropertyName("shinutiHardDuet")] public int ShinutiHardDuet { get; set; } = 0;
[JsonPropertyName("shinutiManiaDuet")] public int ShinutiManiaDuet { get; set; } = 0;
[JsonPropertyName("shinutiUraDuet")] public int ShinutiUraDuet { get; set; } = 0;
[JsonPropertyName("shinutiScoreEasy")] public int ShinutiScoreEasy { get; set; } = 0;
[JsonPropertyName("shinutiScoreNormal")] public int ShinutiScoreNormal { get; set; } = 0;
[JsonPropertyName("shinutiScoreHard")] public int ShinutiScoreHard { get; set; } = 0;
[JsonPropertyName("shinutiScoreMania")] public int ShinutiScoreMania { get; set; } = 0;
[JsonPropertyName("shinutiScoreUra")] public int ShinutiScoreUra { get; set; } = 0;
[JsonPropertyName("shinutiScoreEasyDuet")] public int ShinutiScoreEasyDuet { get; set; } = 0;
[JsonPropertyName("shinutiScoreNormalDuet")] public int ShinutiScoreNormalDuet { get; set; } = 0;
[JsonPropertyName("shinutiScoreHardDuet")] public int ShinutiScoreHardDuet { get; set; } = 0;
[JsonPropertyName("shinutiScoreManiaDuet")] public int ShinutiScoreManiaDuet { get; set; } = 0;
[JsonPropertyName("shinutiScoreUraDuet")] public int ShinutiScoreUraDuet { get; set; } = 0;
[JsonPropertyName("easyOnpuNum")] public int EasyOnpuNum { get; set; } = 0;
[JsonPropertyName("normalOnpuNum")] public int NormalOnpuNum { get; set; } = 0;
[JsonPropertyName("hardOnpuNum")] public int HardOnpuNum { get; set; } = 0;
[JsonPropertyName("maniaOnpuNum")] public int ManiaOnpuNum { get; set; } = 0;
[JsonPropertyName("uraOnpuNum")] public int UraOnpuNum { get; set; } = 0;
[JsonPropertyName("rendaTimeEasy")] public double RendaTimeEasy { get; set; } = 0;
[JsonPropertyName("rendaTimeNormal")] public double RendaTimeNormal { get; set; } = 0;
[JsonPropertyName("rendaTimeHard")] public double RendaTimeHard { get; set; } = 0;
[JsonPropertyName("rendaTimeMania")] public double RendaTimeMania { get; set; } = 0;
[JsonPropertyName("rendaTimeUra")] public double RendaTimeUra { get; set; } = 0;
[JsonPropertyName("fuusenTotalEasy")] public int FuusenTotalEasy { get; set; } = 0;
[JsonPropertyName("fuusenTotalNormal")] public int FuusenTotalNormal { get; set; } = 0;
[JsonPropertyName("fuusenTotalHard")] public int FuusenTotalHard { get; set; } = 0;
[JsonPropertyName("fuusenTotalMania")] public int FuusenTotalMania { get; set; } = 0;
[JsonPropertyName("fuusenTotalUra")] public int FuusenTotalUra { get; set; } = 0;
public override string ToString() => $"{UniqueId}. {Id}";
public MusicInfo Clone()
{
var props = GetType().GetProperties();
var clone = new MusicInfo();
foreach (var p in props)
p.SetValue(clone, p.GetValue(this));
return clone;
}
}
}

10
Data/MusicInfos.cs Normal file
View File

@ -0,0 +1,10 @@
using System.Text.Json.Serialization;
namespace TaikoSoundEditor.Data
{
internal class MusicInfos
{
[JsonPropertyName("items")]
public List<MusicInfo> Items { get; set; } = new List<MusicInfo>();
}
}

20
Data/MusicOrder.cs Normal file
View File

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
namespace TaikoSoundEditor.Data
{
public class MusicOrder
{
[JsonPropertyName("genreNo")] public int GenreNo { get; set; } = 0;
[ReadOnly(true)]
[JsonPropertyName("id")] public string Id { get; set; } = "ABCDEF";
[ReadOnly(true)]
[JsonPropertyName("uniqueId")] public int UniqueId { get; set; } = 0;
[JsonPropertyName("closeDispType")] public int CloseDispType { get; set; } = 0;
}
}

17
Data/MusicOrders.cs Normal file
View File

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
namespace TaikoSoundEditor.Data
{
public class MusicOrders
{
[JsonPropertyName("items")]
public List<MusicOrder> Items { get; set; } = new List<MusicOrder>();
public MusicOrder GetByUniqueId(int id) => Items.Find(i => i.UniqueId == id);
}
}

34
Data/NewSongData.cs Normal file
View File

@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TaikoSoundEditor.Data
{
internal class NewSongData
{
public string Id { get; set; }
public int UniqueId { get; set; }
public byte[] Wav { get; set; }
public byte[] EBin { get; set; }
public byte[] HBin { get; set; }
public byte[] MBin { get; set; }
public byte[] NBin { get; set; }
public byte[] XBin { get; set; }
public byte[] Nus3Bank { get; set; }
public MusicAttribute MusicAttribute { get; set; }
public MusicInfo MusicInfo { get; set; }
public MusicOrder MusicOrder { get; set; }
public Word Word { get; set; }
public Word WordSub { get; set; }
public Word WordDetail { get; set; }
public override string ToString() => $"{UniqueId}. {Id}";
}
}

18
Data/Word.cs Normal file
View File

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
namespace TaikoSoundEditor.Data
{
public class Word
{
[ReadOnly(true)]
[JsonPropertyName("key")] public string Key { get; set; } = "song_...";
[JsonPropertyName("japaneseText")] public string JapaneseText { get; set; } = "text...";
[JsonPropertyName("japaneseFontType")] public int JapaneseFontType { get; set; } = 0;
}
}

19
Data/WordList.cs Normal file
View File

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
namespace TaikoSoundEditor.Data
{
internal class WordList
{
[JsonPropertyName("items")]
public List<Word> Items { get; set; } = new List<Word>();
public Word GetBySong(string song) => Items.Find(i => i.Key == $"song_{song}");
public Word GetBySongSub(string song) => Items.Find(i => i.Key == $"song_sub_{song}");
public Word GetBySongDetail(string song) => Items.Find(i => i.Key == $"song_detail_{song}");
}
}

View File

@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace TaikoSoundEditor.Extensions
{
internal static class StringExtensions
{
public static Match Match(this string s, string regex, string options="")
{
var opts = RegexOptions.None;
if (options.Contains('i')) opts |= RegexOptions.IgnoreCase;
var r = new Regex(regex);
if (!r.IsMatch(s)) return null;
return r.Match(s);
}
}
}

53
GZ.cs Normal file
View File

@ -0,0 +1,53 @@
using System;
using System.Collections.Generic;
using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TaikoSoundEditor
{
internal class GZ
{
public static string DecompressString(string gzPath)
{
using FileStream originalFileStream = File.OpenRead(gzPath);
using GZipStream decompressionStream = new GZipStream(originalFileStream, CompressionMode.Decompress);
using StreamReader reader = new StreamReader(decompressionStream);
return reader.ReadToEnd();
}
public static byte[] DecompressBytes(string gzPath)
{
using FileStream originalFileStream = File.OpenRead(gzPath);
using GZipStream decompressionStream = new GZipStream(originalFileStream, CompressionMode.Decompress);
using MemoryStream ms = new MemoryStream();
decompressionStream.CopyTo(ms);
return ms.ToArray();
}
public static byte[] CompressToBytes(string content)
{
using var stream = new MemoryStream();
using var writer = new StreamWriter(stream);
writer.Write(content);
using var ostream = new MemoryStream();
using (var compressionStream = new GZipStream(ostream, CompressionMode.Compress))
{
stream.CopyTo(compressionStream);
}
return ostream.ToArray();
}
public static void CompressToFile(string fileName, string content)
{
using var stream = new MemoryStream();
using var writer = new StreamWriter(stream);
writer.Write(content);
using FileStream compressedFileStream = File.Create(fileName);
using var compressor = new GZipStream(compressedFileStream, CompressionMode.Compress);
new MemoryStream(stream.ToArray()).CopyTo(compressor);
}
}
}

37
IDSP.cs Normal file
View File

@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TaikoSoundEditor
{
internal static class IDSP
{
public static void WavToIdsp(string source, string dest)
{
source = Path.GetFullPath(source);
dest = Path.GetFullPath(dest);
Debug.WriteLine(source);
Debug.WriteLine(dest);
var p = new Process();
p.StartInfo.FileName = Path.GetFullPath(@"Tools\VGAudio\VGAudioCli.exe");
p.StartInfo.ArgumentList.Add(source);
p.StartInfo.ArgumentList.Add(dest);
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.RedirectStandardOutput = false;
p.Start();
p.WaitForExit();
int exitCode = p.ExitCode;
string stderr = p.StandardError.ReadToEnd();
if (exitCode != 0)
throw new Exception($"Process VGAudioCli failed with exit code {exitCode}:\n" + stderr);
}
}
}

18
Json.cs Normal file
View File

@ -0,0 +1,18 @@
using System.Text.Json;
namespace TaikoSoundEditor
{
internal static class Json
{
public static T Deserialize<T>(string json)
{
return JsonSerializer.Deserialize<T>(json);
}
public static string Serialize<T>(T item)
{
return JsonSerializer.Serialize(item, new JsonSerializerOptions { WriteIndented = true });
}
}
}

835
MainForm.Designer.cs generated Normal file
View File

@ -0,0 +1,835 @@
namespace TaikoSoundEditor
{
partial class MainForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.TabControl = new System.Windows.Forms.TabControl();
this.tabPage1 = new System.Windows.Forms.TabPage();
this.panel1 = new System.Windows.Forms.Panel();
this.OkButton = new System.Windows.Forms.Button();
this.groupBox2 = new System.Windows.Forms.GroupBox();
this.DirSelector = new TaikoSoundEditor.PathSelector();
this.label1 = new System.Windows.Forms.Label();
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.label5 = new System.Windows.Forms.Label();
this.label6 = new System.Windows.Forms.Label();
this.label7 = new System.Windows.Forms.Label();
this.WordListPathSelector = new TaikoSoundEditor.PathSelector();
this.MusicInfoPathSelector = new TaikoSoundEditor.PathSelector();
this.MusicOrderPathSelector = new TaikoSoundEditor.PathSelector();
this.MusicAttributePathSelector = new TaikoSoundEditor.PathSelector();
this.label8 = new System.Windows.Forms.Label();
this.tabPage2 = new System.Windows.Forms.TabPage();
this.ExportOpenOnFinished = new System.Windows.Forms.CheckBox();
this.ExportAllButton = new System.Windows.Forms.Button();
this.ExportSoundBanksButton = new System.Windows.Forms.Button();
this.ExportSoundFoldersButton = new System.Windows.Forms.Button();
this.ExportDatatableButton = new System.Windows.Forms.Button();
this.CreateButton = new System.Windows.Forms.Button();
this.groupBox8 = new System.Windows.Forms.GroupBox();
this.NewSoundsBox = new System.Windows.Forms.ListBox();
this.groupBox4 = new System.Windows.Forms.GroupBox();
this.EditorTable = new System.Windows.Forms.TableLayoutPanel();
this.panel3 = new System.Windows.Forms.Panel();
this.groupBox6 = new System.Windows.Forms.GroupBox();
this.MusicAttributesGrid = new System.Windows.Forms.PropertyGrid();
this.groupBox7 = new System.Windows.Forms.GroupBox();
this.MusicOrderGrid = new System.Windows.Forms.PropertyGrid();
this.groupBox5 = new System.Windows.Forms.GroupBox();
this.MusicInfoGrid = new System.Windows.Forms.PropertyGrid();
this.panel2 = new System.Windows.Forms.Panel();
this.WordDetailGB = new System.Windows.Forms.GroupBox();
this.WordDetailGrid = new System.Windows.Forms.PropertyGrid();
this.WordSubGB = new System.Windows.Forms.GroupBox();
this.WordSubGrid = new System.Windows.Forms.PropertyGrid();
this.WordsGB = new System.Windows.Forms.GroupBox();
this.WordsGrid = new System.Windows.Forms.PropertyGrid();
this.groupBox3 = new System.Windows.Forms.GroupBox();
this.LoadedMusicBox = new System.Windows.Forms.ListBox();
this.tabPage3 = new System.Windows.Forms.TabPage();
this.panel4 = new System.Windows.Forms.Panel();
this.groupBox10 = new System.Windows.Forms.GroupBox();
this.FeedbackBox = new System.Windows.Forms.TextBox();
this.CreateBackButton = new System.Windows.Forms.Button();
this.CreateOkButton = new System.Windows.Forms.Button();
this.label2 = new System.Windows.Forms.Label();
this.SongNameBox = new System.Windows.Forms.TextBox();
this.label9 = new System.Windows.Forms.Label();
this.TJASelector = new TaikoSoundEditor.PathSelector();
this.AudioFileSelector = new TaikoSoundEditor.PathSelector();
this.label10 = new System.Windows.Forms.Label();
this.TabControl.SuspendLayout();
this.tabPage1.SuspendLayout();
this.panel1.SuspendLayout();
this.groupBox2.SuspendLayout();
this.groupBox1.SuspendLayout();
this.tabPage2.SuspendLayout();
this.groupBox8.SuspendLayout();
this.groupBox4.SuspendLayout();
this.EditorTable.SuspendLayout();
this.panel3.SuspendLayout();
this.groupBox6.SuspendLayout();
this.groupBox7.SuspendLayout();
this.groupBox5.SuspendLayout();
this.panel2.SuspendLayout();
this.WordDetailGB.SuspendLayout();
this.WordSubGB.SuspendLayout();
this.WordsGB.SuspendLayout();
this.groupBox3.SuspendLayout();
this.tabPage3.SuspendLayout();
this.panel4.SuspendLayout();
this.groupBox10.SuspendLayout();
this.SuspendLayout();
//
// TabControl
//
this.TabControl.Appearance = System.Windows.Forms.TabAppearance.FlatButtons;
this.TabControl.Controls.Add(this.tabPage1);
this.TabControl.Controls.Add(this.tabPage2);
this.TabControl.Controls.Add(this.tabPage3);
this.TabControl.Dock = System.Windows.Forms.DockStyle.Fill;
this.TabControl.ItemSize = new System.Drawing.Size(0, 1);
this.TabControl.Location = new System.Drawing.Point(0, 0);
this.TabControl.Name = "TabControl";
this.TabControl.SelectedIndex = 0;
this.TabControl.Size = new System.Drawing.Size(684, 461);
this.TabControl.SizeMode = System.Windows.Forms.TabSizeMode.Fixed;
this.TabControl.TabIndex = 0;
//
// tabPage1
//
this.tabPage1.BackColor = System.Drawing.Color.White;
this.tabPage1.Controls.Add(this.panel1);
this.tabPage1.Location = new System.Drawing.Point(4, 5);
this.tabPage1.Name = "tabPage1";
this.tabPage1.Padding = new System.Windows.Forms.Padding(3);
this.tabPage1.Size = new System.Drawing.Size(676, 452);
this.tabPage1.TabIndex = 0;
this.tabPage1.Text = "tabPage1";
//
// panel1
//
this.panel1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
this.panel1.Controls.Add(this.OkButton);
this.panel1.Controls.Add(this.groupBox2);
this.panel1.Controls.Add(this.groupBox1);
this.panel1.Location = new System.Drawing.Point(151, 62);
this.panel1.Name = "panel1";
this.panel1.Size = new System.Drawing.Size(374, 229);
this.panel1.TabIndex = 1;
//
// OkButton
//
this.OkButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.OkButton.Location = new System.Drawing.Point(262, 203);
this.OkButton.Name = "OkButton";
this.OkButton.Size = new System.Drawing.Size(109, 23);
this.OkButton.TabIndex = 10;
this.OkButton.Text = "Looks good";
this.OkButton.UseVisualStyleBackColor = true;
this.OkButton.Click += new System.EventHandler(this.OkButton_Click);
//
// groupBox2
//
this.groupBox2.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.groupBox2.Controls.Add(this.DirSelector);
this.groupBox2.Controls.Add(this.label1);
this.groupBox2.Location = new System.Drawing.Point(3, 141);
this.groupBox2.Name = "groupBox2";
this.groupBox2.Size = new System.Drawing.Size(368, 57);
this.groupBox2.TabIndex = 9;
this.groupBox2.TabStop = false;
this.groupBox2.Text = "Or specify the game diretory (/datatable)";
//
// DirSelector
//
this.DirSelector.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.DirSelector.Filter = "All files(*.*)|*.*";
this.DirSelector.Location = new System.Drawing.Point(68, 22);
this.DirSelector.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
this.DirSelector.Name = "DirSelector";
this.DirSelector.Path = "";
this.DirSelector.SelectsFolder = true;
this.DirSelector.Size = new System.Drawing.Size(293, 23);
this.DirSelector.TabIndex = 11;
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(6, 26);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(55, 15);
this.label1.TabIndex = 10;
this.label1.Text = "Directory";
//
// groupBox1
//
this.groupBox1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.groupBox1.Controls.Add(this.label5);
this.groupBox1.Controls.Add(this.label6);
this.groupBox1.Controls.Add(this.label7);
this.groupBox1.Controls.Add(this.WordListPathSelector);
this.groupBox1.Controls.Add(this.MusicInfoPathSelector);
this.groupBox1.Controls.Add(this.MusicOrderPathSelector);
this.groupBox1.Controls.Add(this.MusicAttributePathSelector);
this.groupBox1.Controls.Add(this.label8);
this.groupBox1.Location = new System.Drawing.Point(3, 3);
this.groupBox1.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(368, 132);
this.groupBox1.TabIndex = 8;
this.groupBox1.TabStop = false;
this.groupBox1.Text = "Select individual files";
//
// label5
//
this.label5.AutoSize = true;
this.label5.Location = new System.Drawing.Point(6, 106);
this.label5.Name = "label5";
this.label5.Size = new System.Drawing.Size(69, 15);
this.label5.TabIndex = 15;
this.label5.Text = "wordlist.bin";
//
// label6
//
this.label6.AutoSize = true;
this.label6.Location = new System.Drawing.Point(6, 77);
this.label6.Name = "label6";
this.label6.Size = new System.Drawing.Size(80, 15);
this.label6.TabIndex = 14;
this.label6.Text = "musicinfo.bin";
//
// label7
//
this.label7.AutoSize = true;
this.label7.Location = new System.Drawing.Point(6, 48);
this.label7.Name = "label7";
this.label7.Size = new System.Drawing.Size(92, 15);
this.label7.TabIndex = 13;
this.label7.Text = "music_order.bin";
//
// WordListPathSelector
//
this.WordListPathSelector.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.WordListPathSelector.Filter = "Binary files(*.bin)|*.bin|All files(*.*)|*.*";
this.WordListPathSelector.Location = new System.Drawing.Point(118, 102);
this.WordListPathSelector.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
this.WordListPathSelector.Name = "WordListPathSelector";
this.WordListPathSelector.Path = "";
this.WordListPathSelector.SelectsFolder = false;
this.WordListPathSelector.Size = new System.Drawing.Size(243, 23);
this.WordListPathSelector.TabIndex = 12;
//
// MusicInfoPathSelector
//
this.MusicInfoPathSelector.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.MusicInfoPathSelector.Filter = "Binary files(*.bin)|*.bin|All files(*.*)|*.*";
this.MusicInfoPathSelector.Location = new System.Drawing.Point(118, 73);
this.MusicInfoPathSelector.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
this.MusicInfoPathSelector.Name = "MusicInfoPathSelector";
this.MusicInfoPathSelector.Path = "";
this.MusicInfoPathSelector.SelectsFolder = false;
this.MusicInfoPathSelector.Size = new System.Drawing.Size(243, 23);
this.MusicInfoPathSelector.TabIndex = 11;
//
// MusicOrderPathSelector
//
this.MusicOrderPathSelector.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.MusicOrderPathSelector.Filter = "Binary files(*.bin)|*.bin|All files(*.*)|*.*";
this.MusicOrderPathSelector.Location = new System.Drawing.Point(118, 44);
this.MusicOrderPathSelector.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
this.MusicOrderPathSelector.Name = "MusicOrderPathSelector";
this.MusicOrderPathSelector.Path = "";
this.MusicOrderPathSelector.SelectsFolder = false;
this.MusicOrderPathSelector.Size = new System.Drawing.Size(243, 23);
this.MusicOrderPathSelector.TabIndex = 10;
//
// MusicAttributePathSelector
//
this.MusicAttributePathSelector.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.MusicAttributePathSelector.Filter = "Binary files(*.bin)|*.bin|All files(*.*)|*.*";
this.MusicAttributePathSelector.Location = new System.Drawing.Point(118, 15);
this.MusicAttributePathSelector.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
this.MusicAttributePathSelector.Name = "MusicAttributePathSelector";
this.MusicAttributePathSelector.Path = "";
this.MusicAttributePathSelector.SelectsFolder = false;
this.MusicAttributePathSelector.Size = new System.Drawing.Size(243, 23);
this.MusicAttributePathSelector.TabIndex = 9;
//
// label8
//
this.label8.AutoSize = true;
this.label8.Location = new System.Drawing.Point(6, 19);
this.label8.Name = "label8";
this.label8.Size = new System.Drawing.Size(105, 15);
this.label8.TabIndex = 8;
this.label8.Text = "music_atribute.bin";
//
// tabPage2
//
this.tabPage2.Controls.Add(this.ExportOpenOnFinished);
this.tabPage2.Controls.Add(this.ExportAllButton);
this.tabPage2.Controls.Add(this.ExportSoundBanksButton);
this.tabPage2.Controls.Add(this.ExportSoundFoldersButton);
this.tabPage2.Controls.Add(this.ExportDatatableButton);
this.tabPage2.Controls.Add(this.CreateButton);
this.tabPage2.Controls.Add(this.groupBox8);
this.tabPage2.Controls.Add(this.groupBox4);
this.tabPage2.Controls.Add(this.groupBox3);
this.tabPage2.Location = new System.Drawing.Point(4, 5);
this.tabPage2.Name = "tabPage2";
this.tabPage2.Padding = new System.Windows.Forms.Padding(3);
this.tabPage2.Size = new System.Drawing.Size(676, 452);
this.tabPage2.TabIndex = 1;
this.tabPage2.Text = "tabPage2";
this.tabPage2.UseVisualStyleBackColor = true;
//
// ExportOpenOnFinished
//
this.ExportOpenOnFinished.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.ExportOpenOnFinished.AutoSize = true;
this.ExportOpenOnFinished.Location = new System.Drawing.Point(318, 425);
this.ExportOpenOnFinished.Name = "ExportOpenOnFinished";
this.ExportOpenOnFinished.Size = new System.Drawing.Size(203, 19);
this.ExportOpenOnFinished.TabIndex = 10;
this.ExportOpenOnFinished.Text = "Open folder when export finished";
this.ExportOpenOnFinished.UseVisualStyleBackColor = true;
//
// ExportAllButton
//
this.ExportAllButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.ExportAllButton.Location = new System.Drawing.Point(528, 423);
this.ExportAllButton.Name = "ExportAllButton";
this.ExportAllButton.Size = new System.Drawing.Size(142, 23);
this.ExportAllButton.TabIndex = 9;
this.ExportAllButton.Text = "Export All";
this.ExportAllButton.UseVisualStyleBackColor = true;
this.ExportAllButton.Click += new System.EventHandler(this.ExportAllButton_Click);
//
// ExportSoundBanksButton
//
this.ExportSoundBanksButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.ExportSoundBanksButton.Location = new System.Drawing.Point(528, 395);
this.ExportSoundBanksButton.Name = "ExportSoundBanksButton";
this.ExportSoundBanksButton.Size = new System.Drawing.Size(142, 23);
this.ExportSoundBanksButton.TabIndex = 8;
this.ExportSoundBanksButton.Text = "Export Sound Banks";
this.ExportSoundBanksButton.UseVisualStyleBackColor = true;
this.ExportSoundBanksButton.Click += new System.EventHandler(this.ExportSoundBanksButton_Click);
//
// ExportSoundFoldersButton
//
this.ExportSoundFoldersButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.ExportSoundFoldersButton.Location = new System.Drawing.Point(528, 366);
this.ExportSoundFoldersButton.Name = "ExportSoundFoldersButton";
this.ExportSoundFoldersButton.Size = new System.Drawing.Size(142, 23);
this.ExportSoundFoldersButton.TabIndex = 7;
this.ExportSoundFoldersButton.Text = "Export Sound Folders";
this.ExportSoundFoldersButton.UseVisualStyleBackColor = true;
this.ExportSoundFoldersButton.Click += new System.EventHandler(this.ExportSoundFoldersButton_Click);
//
// ExportDatatableButton
//
this.ExportDatatableButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.ExportDatatableButton.Location = new System.Drawing.Point(528, 337);
this.ExportDatatableButton.Name = "ExportDatatableButton";
this.ExportDatatableButton.Size = new System.Drawing.Size(142, 23);
this.ExportDatatableButton.TabIndex = 6;
this.ExportDatatableButton.Text = "Export Datatable";
this.ExportDatatableButton.UseVisualStyleBackColor = true;
this.ExportDatatableButton.Click += new System.EventHandler(this.ExportDatatableButton_Click);
//
// CreateButton
//
this.CreateButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.CreateButton.Location = new System.Drawing.Point(139, 343);
this.CreateButton.Name = "CreateButton";
this.CreateButton.Size = new System.Drawing.Size(75, 23);
this.CreateButton.TabIndex = 5;
this.CreateButton.Text = "Create...";
this.CreateButton.UseVisualStyleBackColor = true;
this.CreateButton.Click += new System.EventHandler(this.CreateButton_Click);
//
// groupBox8
//
this.groupBox8.Controls.Add(this.NewSoundsBox);
this.groupBox8.Location = new System.Drawing.Point(8, 212);
this.groupBox8.Name = "groupBox8";
this.groupBox8.Size = new System.Drawing.Size(125, 213);
this.groupBox8.TabIndex = 3;
this.groupBox8.TabStop = false;
this.groupBox8.Text = "New Sounds List";
//
// NewSoundsBox
//
this.NewSoundsBox.Dock = System.Windows.Forms.DockStyle.Fill;
this.NewSoundsBox.FormattingEnabled = true;
this.NewSoundsBox.ItemHeight = 15;
this.NewSoundsBox.Location = new System.Drawing.Point(3, 19);
this.NewSoundsBox.Name = "NewSoundsBox";
this.NewSoundsBox.Size = new System.Drawing.Size(119, 191);
this.NewSoundsBox.TabIndex = 1;
this.NewSoundsBox.SelectedIndexChanged += new System.EventHandler(this.NewSoundsBox_SelectedIndexChanged);
//
// groupBox4
//
this.groupBox4.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.groupBox4.Controls.Add(this.EditorTable);
this.groupBox4.Location = new System.Drawing.Point(139, 6);
this.groupBox4.Name = "groupBox4";
this.groupBox4.Size = new System.Drawing.Size(531, 331);
this.groupBox4.TabIndex = 4;
this.groupBox4.TabStop = false;
this.groupBox4.Text = "Sound Data";
//
// EditorTable
//
this.EditorTable.ColumnCount = 3;
this.EditorTable.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33F));
this.EditorTable.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 34F));
this.EditorTable.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33F));
this.EditorTable.Controls.Add(this.panel3, 1, 0);
this.EditorTable.Controls.Add(this.groupBox5, 0, 0);
this.EditorTable.Controls.Add(this.panel2, 2, 0);
this.EditorTable.Dock = System.Windows.Forms.DockStyle.Fill;
this.EditorTable.Location = new System.Drawing.Point(3, 19);
this.EditorTable.Name = "EditorTable";
this.EditorTable.RowCount = 1;
this.EditorTable.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.EditorTable.Size = new System.Drawing.Size(525, 309);
this.EditorTable.TabIndex = 7;
this.EditorTable.Resize += new System.EventHandler(this.EditorTable_Resize);
//
// panel3
//
this.panel3.Controls.Add(this.groupBox6);
this.panel3.Controls.Add(this.groupBox7);
this.panel3.Dock = System.Windows.Forms.DockStyle.Fill;
this.panel3.Location = new System.Drawing.Point(176, 3);
this.panel3.Name = "panel3";
this.panel3.Size = new System.Drawing.Size(172, 303);
this.panel3.TabIndex = 5;
//
// groupBox6
//
this.groupBox6.Controls.Add(this.MusicAttributesGrid);
this.groupBox6.Dock = System.Windows.Forms.DockStyle.Fill;
this.groupBox6.Location = new System.Drawing.Point(0, 0);
this.groupBox6.Name = "groupBox6";
this.groupBox6.Size = new System.Drawing.Size(172, 179);
this.groupBox6.TabIndex = 5;
this.groupBox6.TabStop = false;
this.groupBox6.Text = "Music Attributes";
//
// MusicAttributesGrid
//
this.MusicAttributesGrid.Dock = System.Windows.Forms.DockStyle.Fill;
this.MusicAttributesGrid.HelpVisible = false;
this.MusicAttributesGrid.Location = new System.Drawing.Point(3, 19);
this.MusicAttributesGrid.Name = "MusicAttributesGrid";
this.MusicAttributesGrid.Size = new System.Drawing.Size(166, 157);
this.MusicAttributesGrid.TabIndex = 3;
this.MusicAttributesGrid.ToolbarVisible = false;
//
// groupBox7
//
this.groupBox7.Controls.Add(this.MusicOrderGrid);
this.groupBox7.Dock = System.Windows.Forms.DockStyle.Bottom;
this.groupBox7.Location = new System.Drawing.Point(0, 179);
this.groupBox7.Name = "groupBox7";
this.groupBox7.Size = new System.Drawing.Size(172, 124);
this.groupBox7.TabIndex = 6;
this.groupBox7.TabStop = false;
this.groupBox7.Text = "Music Order";
//
// MusicOrderGrid
//
this.MusicOrderGrid.Dock = System.Windows.Forms.DockStyle.Fill;
this.MusicOrderGrid.HelpVisible = false;
this.MusicOrderGrid.Location = new System.Drawing.Point(3, 19);
this.MusicOrderGrid.Name = "MusicOrderGrid";
this.MusicOrderGrid.Size = new System.Drawing.Size(166, 102);
this.MusicOrderGrid.TabIndex = 3;
this.MusicOrderGrid.ToolbarVisible = false;
//
// groupBox5
//
this.groupBox5.Controls.Add(this.MusicInfoGrid);
this.groupBox5.Dock = System.Windows.Forms.DockStyle.Fill;
this.groupBox5.Location = new System.Drawing.Point(3, 3);
this.groupBox5.Name = "groupBox5";
this.groupBox5.Size = new System.Drawing.Size(167, 303);
this.groupBox5.TabIndex = 4;
this.groupBox5.TabStop = false;
this.groupBox5.Text = "Music Info";
//
// MusicInfoGrid
//
this.MusicInfoGrid.Dock = System.Windows.Forms.DockStyle.Fill;
this.MusicInfoGrid.HelpVisible = false;
this.MusicInfoGrid.Location = new System.Drawing.Point(3, 19);
this.MusicInfoGrid.Name = "MusicInfoGrid";
this.MusicInfoGrid.Size = new System.Drawing.Size(161, 281);
this.MusicInfoGrid.TabIndex = 3;
this.MusicInfoGrid.ToolbarVisible = false;
//
// panel2
//
this.panel2.Controls.Add(this.WordDetailGB);
this.panel2.Controls.Add(this.WordSubGB);
this.panel2.Controls.Add(this.WordsGB);
this.panel2.Dock = System.Windows.Forms.DockStyle.Fill;
this.panel2.Location = new System.Drawing.Point(354, 3);
this.panel2.Name = "panel2";
this.panel2.Size = new System.Drawing.Size(168, 303);
this.panel2.TabIndex = 6;
//
// WordDetailGB
//
this.WordDetailGB.Controls.Add(this.WordDetailGrid);
this.WordDetailGB.Dock = System.Windows.Forms.DockStyle.Top;
this.WordDetailGB.Location = new System.Drawing.Point(0, 184);
this.WordDetailGB.Name = "WordDetailGB";
this.WordDetailGB.Size = new System.Drawing.Size(168, 96);
this.WordDetailGB.TabIndex = 8;
this.WordDetailGB.TabStop = false;
this.WordDetailGB.Text = "Word Detail";
//
// WordDetailGrid
//
this.WordDetailGrid.Dock = System.Windows.Forms.DockStyle.Fill;
this.WordDetailGrid.HelpVisible = false;
this.WordDetailGrid.Location = new System.Drawing.Point(3, 19);
this.WordDetailGrid.Name = "WordDetailGrid";
this.WordDetailGrid.Size = new System.Drawing.Size(162, 74);
this.WordDetailGrid.TabIndex = 3;
this.WordDetailGrid.ToolbarVisible = false;
//
// WordSubGB
//
this.WordSubGB.Controls.Add(this.WordSubGrid);
this.WordSubGB.Dock = System.Windows.Forms.DockStyle.Top;
this.WordSubGB.Location = new System.Drawing.Point(0, 88);
this.WordSubGB.Name = "WordSubGB";
this.WordSubGB.Size = new System.Drawing.Size(168, 96);
this.WordSubGB.TabIndex = 7;
this.WordSubGB.TabStop = false;
this.WordSubGB.Text = "Word Sub";
//
// WordSubGrid
//
this.WordSubGrid.Dock = System.Windows.Forms.DockStyle.Fill;
this.WordSubGrid.HelpVisible = false;
this.WordSubGrid.Location = new System.Drawing.Point(3, 19);
this.WordSubGrid.Name = "WordSubGrid";
this.WordSubGrid.Size = new System.Drawing.Size(162, 74);
this.WordSubGrid.TabIndex = 3;
this.WordSubGrid.ToolbarVisible = false;
//
// WordsGB
//
this.WordsGB.Controls.Add(this.WordsGrid);
this.WordsGB.Dock = System.Windows.Forms.DockStyle.Top;
this.WordsGB.Location = new System.Drawing.Point(0, 0);
this.WordsGB.Name = "WordsGB";
this.WordsGB.Size = new System.Drawing.Size(168, 88);
this.WordsGB.TabIndex = 6;
this.WordsGB.TabStop = false;
this.WordsGB.Text = "Words";
//
// WordsGrid
//
this.WordsGrid.Dock = System.Windows.Forms.DockStyle.Fill;
this.WordsGrid.HelpVisible = false;
this.WordsGrid.Location = new System.Drawing.Point(3, 19);
this.WordsGrid.Name = "WordsGrid";
this.WordsGrid.PropertySort = System.Windows.Forms.PropertySort.Alphabetical;
this.WordsGrid.Size = new System.Drawing.Size(162, 66);
this.WordsGrid.TabIndex = 3;
this.WordsGrid.ToolbarVisible = false;
//
// groupBox3
//
this.groupBox3.Controls.Add(this.LoadedMusicBox);
this.groupBox3.Location = new System.Drawing.Point(8, 6);
this.groupBox3.Name = "groupBox3";
this.groupBox3.Size = new System.Drawing.Size(125, 203);
this.groupBox3.TabIndex = 2;
this.groupBox3.TabStop = false;
this.groupBox3.Text = "Sounds List";
//
// LoadedMusicBox
//
this.LoadedMusicBox.Dock = System.Windows.Forms.DockStyle.Fill;
this.LoadedMusicBox.FormattingEnabled = true;
this.LoadedMusicBox.ItemHeight = 15;
this.LoadedMusicBox.Location = new System.Drawing.Point(3, 19);
this.LoadedMusicBox.Name = "LoadedMusicBox";
this.LoadedMusicBox.Size = new System.Drawing.Size(119, 181);
this.LoadedMusicBox.TabIndex = 1;
this.LoadedMusicBox.SelectedIndexChanged += new System.EventHandler(this.LoadedMusicBox_SelectedIndexChanged);
//
// tabPage3
//
this.tabPage3.Controls.Add(this.panel4);
this.tabPage3.Location = new System.Drawing.Point(4, 5);
this.tabPage3.Name = "tabPage3";
this.tabPage3.Padding = new System.Windows.Forms.Padding(3);
this.tabPage3.Size = new System.Drawing.Size(676, 452);
this.tabPage3.TabIndex = 2;
this.tabPage3.Text = "tabPage3";
this.tabPage3.UseVisualStyleBackColor = true;
//
// panel4
//
this.panel4.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
this.panel4.Controls.Add(this.groupBox10);
this.panel4.Location = new System.Drawing.Point(151, 102);
this.panel4.Name = "panel4";
this.panel4.Size = new System.Drawing.Size(374, 235);
this.panel4.TabIndex = 2;
//
// groupBox10
//
this.groupBox10.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.groupBox10.Controls.Add(this.FeedbackBox);
this.groupBox10.Controls.Add(this.CreateBackButton);
this.groupBox10.Controls.Add(this.CreateOkButton);
this.groupBox10.Controls.Add(this.label2);
this.groupBox10.Controls.Add(this.SongNameBox);
this.groupBox10.Controls.Add(this.label9);
this.groupBox10.Controls.Add(this.TJASelector);
this.groupBox10.Controls.Add(this.AudioFileSelector);
this.groupBox10.Controls.Add(this.label10);
this.groupBox10.Location = new System.Drawing.Point(3, 3);
this.groupBox10.Name = "groupBox10";
this.groupBox10.Size = new System.Drawing.Size(368, 215);
this.groupBox10.TabIndex = 8;
this.groupBox10.TabStop = false;
this.groupBox10.Text = "Create new sound";
//
// FeedbackBox
//
this.FeedbackBox.Location = new System.Drawing.Point(6, 134);
this.FeedbackBox.Multiline = true;
this.FeedbackBox.Name = "FeedbackBox";
this.FeedbackBox.Size = new System.Drawing.Size(356, 75);
this.FeedbackBox.TabIndex = 18;
//
// CreateBackButton
//
this.CreateBackButton.Location = new System.Drawing.Point(205, 102);
this.CreateBackButton.Name = "CreateBackButton";
this.CreateBackButton.Size = new System.Drawing.Size(75, 23);
this.CreateBackButton.TabIndex = 17;
this.CreateBackButton.Text = "Back";
this.CreateBackButton.UseVisualStyleBackColor = true;
this.CreateBackButton.Click += new System.EventHandler(this.CreateBackButton_Click);
//
// CreateOkButton
//
this.CreateOkButton.Location = new System.Drawing.Point(286, 102);
this.CreateOkButton.Name = "CreateOkButton";
this.CreateOkButton.Size = new System.Drawing.Size(75, 23);
this.CreateOkButton.TabIndex = 16;
this.CreateOkButton.Text = "Ok";
this.CreateOkButton.UseVisualStyleBackColor = true;
this.CreateOkButton.Click += new System.EventHandler(this.CreateOkButton_Click);
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(6, 76);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(67, 15);
this.label2.TabIndex = 15;
this.label2.Text = "Song name";
//
// SongNameBox
//
this.SongNameBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.SongNameBox.Location = new System.Drawing.Point(79, 73);
this.SongNameBox.Name = "SongNameBox";
this.SongNameBox.Size = new System.Drawing.Size(283, 23);
this.SongNameBox.TabIndex = 14;
this.SongNameBox.Text = "(6 characters id...)";
//
// label9
//
this.label9.AutoSize = true;
this.label9.Location = new System.Drawing.Point(6, 48);
this.label9.Name = "label9";
this.label9.Size = new System.Drawing.Size(43, 15);
this.label9.TabIndex = 13;
this.label9.Text = "TJA file";
//
// TJASelector
//
this.TJASelector.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.TJASelector.Filter = ".tja files(*.tja)|*.tja|All files(*.*)|*.*";
this.TJASelector.Location = new System.Drawing.Point(79, 44);
this.TJASelector.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
this.TJASelector.Name = "TJASelector";
this.TJASelector.Path = "";
this.TJASelector.SelectsFolder = false;
this.TJASelector.Size = new System.Drawing.Size(282, 23);
this.TJASelector.TabIndex = 10;
this.TJASelector.PathChanged += new TaikoSoundEditor.PathSelector.OnPathChanged(this.TJASelector_PathChanged);
//
// AudioFileSelector
//
this.AudioFileSelector.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.AudioFileSelector.Filter = "OGG files(*.ogg)|*.ogg|mp3 files(*.mp3)|*.mp3|WAV files(*.wav)|*.wav|All files(*." +
"*)|*.*";
this.AudioFileSelector.Location = new System.Drawing.Point(79, 15);
this.AudioFileSelector.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
this.AudioFileSelector.Name = "AudioFileSelector";
this.AudioFileSelector.Path = "";
this.AudioFileSelector.SelectsFolder = false;
this.AudioFileSelector.Size = new System.Drawing.Size(282, 23);
this.AudioFileSelector.TabIndex = 9;
//
// label10
//
this.label10.AutoSize = true;
this.label10.Location = new System.Drawing.Point(6, 19);
this.label10.Name = "label10";
this.label10.Size = new System.Drawing.Size(58, 15);
this.label10.TabIndex = 8;
this.label10.Text = "Audio file";
//
// MainForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.Color.White;
this.ClientSize = new System.Drawing.Size(684, 461);
this.Controls.Add(this.TabControl);
this.MinimumSize = new System.Drawing.Size(700, 500);
this.Name = "MainForm";
this.Text = "Taiko Sound Editor";
this.TabControl.ResumeLayout(false);
this.tabPage1.ResumeLayout(false);
this.panel1.ResumeLayout(false);
this.groupBox2.ResumeLayout(false);
this.groupBox2.PerformLayout();
this.groupBox1.ResumeLayout(false);
this.groupBox1.PerformLayout();
this.tabPage2.ResumeLayout(false);
this.tabPage2.PerformLayout();
this.groupBox8.ResumeLayout(false);
this.groupBox4.ResumeLayout(false);
this.EditorTable.ResumeLayout(false);
this.panel3.ResumeLayout(false);
this.groupBox6.ResumeLayout(false);
this.groupBox7.ResumeLayout(false);
this.groupBox5.ResumeLayout(false);
this.panel2.ResumeLayout(false);
this.WordDetailGB.ResumeLayout(false);
this.WordSubGB.ResumeLayout(false);
this.WordsGB.ResumeLayout(false);
this.groupBox3.ResumeLayout(false);
this.tabPage3.ResumeLayout(false);
this.panel4.ResumeLayout(false);
this.groupBox10.ResumeLayout(false);
this.groupBox10.PerformLayout();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.TabControl TabControl;
private System.Windows.Forms.TabPage tabPage1;
private System.Windows.Forms.TabPage tabPage2;
private Panel panel1;
private GroupBox groupBox1;
private Label label5;
private Label label6;
private Label label7;
private PathSelector WordListPathSelector;
private PathSelector MusicInfoPathSelector;
private PathSelector MusicOrderPathSelector;
private PathSelector MusicAttributePathSelector;
private Label label8;
private GroupBox groupBox2;
private Button OkButton;
private PathSelector DirSelector;
private Label label1;
private ListBox LoadedMusicBox;
private GroupBox groupBox3;
private PropertyGrid MusicInfoGrid;
private GroupBox groupBox4;
private GroupBox groupBox5;
private GroupBox groupBox6;
private PropertyGrid MusicAttributesGrid;
private GroupBox WordsGB;
private PropertyGrid WordsGrid;
private TableLayoutPanel EditorTable;
private Panel panel2;
private GroupBox WordDetailGB;
private PropertyGrid WordDetailGrid;
private GroupBox WordSubGB;
private PropertyGrid WordSubGrid;
private Panel panel3;
private GroupBox groupBox7;
private PropertyGrid MusicOrderGrid;
private GroupBox groupBox8;
private ListBox NewSoundsBox;
private Button CreateButton;
private TabPage tabPage3;
private Panel panel4;
private GroupBox groupBox10;
private Label label9;
private PathSelector TJASelector;
private PathSelector AudioFileSelector;
private Label label10;
private TextBox SongNameBox;
private Label label2;
private Button CreateOkButton;
private Button CreateBackButton;
private TextBox FeedbackBox;
private Button ExportAllButton;
private Button ExportSoundBanksButton;
private Button ExportSoundFoldersButton;
private Button ExportDatatableButton;
private CheckBox ExportOpenOnFinished;
}
}

485
MainForm.cs Normal file
View File

@ -0,0 +1,485 @@
using System.ComponentModel;
using System.Diagnostics;
using System.Threading.Tasks.Dataflow;
using TaikoSoundEditor.Data;
namespace TaikoSoundEditor
{
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
MusicAttributePathSelector.PathChanged += MusicAttributePathSelector_PathChanged;
MusicOrderPathSelector.PathChanged += MusicOrderPathSelector_PathChanged;
MusicInfoPathSelector.PathChanged += MusicInfoPathSelector_PathChanged;
WordListPathSelector.PathChanged += WordListPathSelector_PathChanged;
DirSelector.PathChanged += DirSelector_PathChanged;
AddedMusicBinding = new BindingSource();
AddedMusicBinding.DataSource = AddedMusic;
NewSoundsBox.DataSource = AddedMusicBinding;
}
private string MusicAttributePath { get; set; }
private string MusicOrderPath { get; set; }
private string MusicInfoPath { get; set; }
private string WordListPath { get; set; }
private MusicAttributes MusicAttributes;
private MusicOrders MusicOrders;
private WordList WordList;
private MusicInfos MusicInfos;
private List<NewSongData> AddedMusic { get; set; } = new List<NewSongData>();
private BindingSource AddedMusicBinding { get; set; }
#region Requesting Files
private void WordListPathSelector_PathChanged(object sender, EventArgs args)
{
WordListPath = WordListPathSelector.Path;
}
private void MusicInfoPathSelector_PathChanged(object sender, EventArgs args)
{
MusicInfoPath = MusicInfoPathSelector.Path;
}
private void MusicOrderPathSelector_PathChanged(object sender, EventArgs args)
{
MusicOrderPath = MusicOrderPathSelector.Path;
}
private void MusicAttributePathSelector_PathChanged(object sender, EventArgs args)
{
MusicAttributePath = MusicAttributePathSelector.Path;
}
private void DirSelector_PathChanged(object sender, EventArgs args) => RunGuard(() =>
{
var dir = DirSelector.Path;
var files = new string[] { "music_attribute.bin", "music_order.bin", "musicinfo.bin", "wordlist.bin" };
var sels = new PathSelector[] { MusicAttributePathSelector, MusicOrderPathSelector, MusicInfoPathSelector, WordListPathSelector };
List<string> NotFoundFiles = new List<string>();
for (int i = 0; i < files.Length; i++)
{
var path = Path.Combine(dir, files[i]);
if (!File.Exists(path))
{
NotFoundFiles.Add(files[i]);
continue;
}
sels[i].Path = path;
}
if (NotFoundFiles.Count > 0)
{
MessageBox.Show("The following files could not be found:\n\n" + String.Join("\n", NotFoundFiles));
}
});
private void OkButton_Click(object sender, EventArgs e) => RunGuard(() =>
{
MusicAttributes = Json.Deserialize<MusicAttributes>(GZ.DecompressString(MusicAttributePath));
MusicOrders = Json.Deserialize<MusicOrders>(GZ.DecompressString(MusicOrderPath));
MusicInfos = Json.Deserialize<MusicInfos>(GZ.DecompressString(MusicInfoPath));
WordList = Json.Deserialize<WordList>(GZ.DecompressString(WordListPath));
LoadedMusicBox.DataSource = MusicInfos.Items;
TabControl.SelectedIndex = 1;
});
#endregion
public static void RunGuard(Action action)
{
try
{
action();
}
catch (Exception ex)
{
Error(ex);
}
}
public static void Error(Exception e)
{
MessageBox.Show(e.Message, "An error has occured");
}
#region Editor
private void GridsShow(MusicInfo item)
{
MusicInfoGrid.SelectedObject = item;
MusicAttributesGrid.SelectedObject = MusicAttributes.GetByUniqueId(item.UniqueId);
MusicOrderGrid.SelectedObject = MusicOrders.GetByUniqueId(item.UniqueId);
WordsGrid.SelectedObject = WordList.GetBySong(item.Id);
WordSubGrid.SelectedObject = WordList.GetBySongSub(item.Id);
WordDetailGrid.SelectedObject = WordList.GetBySongDetail(item.Id);
}
private void LoadedMusicBox_SelectedIndexChanged(object sender, EventArgs e)
{
var item = LoadedMusicBox.SelectedItem as MusicInfo;
GridsShow(item);
}
private void EditorTable_Resize(object sender, EventArgs e)
{
WordsGB.Height = WordSubGB.Height = WordDetailGB.Height = EditorTable.Height / 3;
}
private void NewSoundsBox_SelectedIndexChanged(object sender, EventArgs e)
{
var item = NewSoundsBox.SelectedItem as NewSongData;
MusicInfoGrid.SelectedObject = item?.MusicInfo;
MusicAttributesGrid.SelectedObject = item?.MusicAttribute;
MusicOrderGrid.SelectedObject = item?.MusicOrder;
WordsGrid.SelectedObject = item?.Word;
WordSubGrid.SelectedObject = item?.WordSub;
WordDetailGrid.SelectedObject = item?.WordDetail;
}
#endregion
private void CreateButton_Click(object sender, EventArgs e)
{
AudioFileSelector.Path = "";
TJASelector.Path = "";
SongNameBox.Text = "(6 characters id...)";
TabControl.SelectedIndex = 2;
}
private void CreateBackButton_Click(object sender, EventArgs e)
{
TabControl.SelectedIndex = 1;
}
private void CreateOkButton_Click(object sender, EventArgs e) => RunGuard(() =>
{
FeedbackBox.Clear();
var audioFilePath = AudioFileSelector.Path;
var tjaPath = TJASelector.Path;
var songName = SongNameBox.Text;
var id = Math.Max(MusicAttributes.GetNewId(), AddedMusic.Count == 0 ? 0 : AddedMusic.Max(_ => _.UniqueId) + 1);
if(songName==null || songName.Length!=6)
{
MessageBox.Show("Invalid song name.");
return;
}
if (!MusicAttributes.IsValidSongId(songName) || AddedMusic.Any(m => m.Id == songName))
{
MessageBox.Show("Duplicate song name. Choose another");
return;
}
FeedbackBox.AppendText("Creating temp dir\r\n");
CreateTmpDir();
FeedbackBox.AppendText("Converting to wav\r\n");
WAV.ConvertToWav(audioFilePath, $@".-tmp\{songName}.wav");
FeedbackBox.AppendText("Running tja2fumen\r\n");
var tja_binaries = TJA.RunTja2Fumen(tjaPath);
FeedbackBox.AppendText("Creating sound data\r\n");
NewSongData ns = new NewSongData();
ns.UniqueId = id;
ns.Id = songName;
ns.Wav = File.ReadAllBytes($@".-tmp\{songName}.wav");
ns.EBin = tja_binaries[0];
ns.HBin = tja_binaries[1];
ns.MBin = tja_binaries[2];
ns.NBin = tja_binaries[3];
var selectedMusicInfo = LoadedMusicBox.SelectedItem as MusicInfo;
var mi = selectedMusicInfo.Clone();
mi.Id = songName;
mi.UniqueId = id;
ns.MusicInfo = mi;
var mo = new MusicOrder();
mo.Id = songName;
mo.UniqueId = id;
ns.MusicOrder = mo;
var ma = MusicAttributes.GetByUniqueId(selectedMusicInfo.UniqueId).Clone();
ma.Id = songName;
ma.UniqueId = id;
ma.New = true;
ns.MusicAttribute = ma;
FeedbackBox.AppendText("Parsing TJA\r\n");
var tja = new TJA(File.ReadAllLines(tjaPath));
File.WriteAllText("tja.txt", tja.ToString());
ns.Word = new Word { Key = $"song_{songName}", JapaneseText = tja.Headers.Title };
ns.WordSub = new Word { Key = $"song_sub_{songName}", JapaneseText = tja.Headers.Subtitle };
ns.WordDetail = new Word { Key = $"song_detail_{songName}", JapaneseText = "[song details...]" };
mi.EasyOnpuNum = tja.Courses[0].Converted.Notes.Length;
mi.NormalOnpuNum = tja.Courses[1].Converted.Notes.Length;
mi.HardOnpuNum = tja.Courses[2].Converted.Notes.Length;
mi.ManiaOnpuNum = tja.Courses[3].Converted.Notes.Length;
mi.StarEasy = tja.Courses[0].Headers.Level;
mi.StarNormal = tja.Courses[1].Headers.Level;
mi.StarHard = tja.Courses[2].Headers.Level;
mi.StarMania = tja.Courses[3].Headers.Level;
if (tja.Courses.ContainsKey(4))
{
FeedbackBox.AppendText("URA course detected\r\n");
mi.UraOnpuNum = tja.Courses[4].Converted.Notes.Length;
mi.StarUra = tja.Courses[4].Headers.Level;
ma.CanPlayUra = true;
}
else
{
ma.CanPlayUra = false;
}
FeedbackBox.AppendText("Adjusting shinuti\r\n");
mi.ShinutiEasy = (mi.ShinutiScoreEasy / mi.EasyOnpuNum) / 10 * 10;
mi.ShinutiNormal = (mi.ShinutiScoreNormal / mi.NormalOnpuNum) / 10 * 10;
mi.ShinutiHard = (mi.ShinutiScoreHard / mi.HardOnpuNum) / 10 * 10;
mi.ShinutiMania = (mi.ShinutiScoreMania / mi.ManiaOnpuNum) / 10 * 10;
mi.ShinutiEasyDuet = (mi.ShinutiScoreEasyDuet / mi.EasyOnpuNum) / 10 * 10;
mi.ShinutiNormalDuet = (mi.ShinutiScoreNormalDuet / mi.NormalOnpuNum) / 10 * 10;
mi.ShinutiHardDuet = (mi.ShinutiScoreHardDuet / mi.HardOnpuNum) / 10 * 10;
mi.ShinutiManiaDuet = (mi.ShinutiScoreManiaDuet / mi.ManiaOnpuNum) / 10 * 10;
if (ma.CanPlayUra)
{
mi.ShinutiUra = (mi.ShinutiScoreUra / mi.UraOnpuNum) / 10 * 10;
mi.ShinutiUraDuet = (mi.ShinutiScoreUraDuet / mi.UraOnpuNum) / 10 * 10;
}
if(ma.CanPlayUra)
{
ns.XBin = tja_binaries[4];
}
mi.SongFileName = $"sound/song_{songName}";
Dictionary<string, int> genres = new Dictionary<string, int>
{
{ "POP", 0 },
{ "ANIME", 1 },
{ "KIDS", 2 },
{ "VOCALOID", 3 },
{ "GAME MUSIC", 4 },
{ "NAMCO ORIGINAL", 5 },
};
if (tja.Headers.Genre != null && genres.ContainsKey(tja.Headers.Genre.ToUpper()))
mi.GenreNo = genres[tja.Headers.Genre.ToUpper()];
FeedbackBox.AppendText("Converting to idsp\r\n");
IDSP.WavToIdsp($@".-tmp\{songName}.wav", $@".-tmp\{songName}.idsp");
var idsp = File.ReadAllBytes($@".-tmp\{songName}.idsp");
FeedbackBox.AppendText("Creating nus3bank file\r\n");
ns.Nus3Bank = NUS3Bank.GetNus3Bank(songName, id, idsp, tja.Headers.DemoStart);
FeedbackBox.AppendText("Done\r\n");
AddedMusic.Add(ns);
AddedMusicBinding.ResetBindings(false);
NewSoundsBox.ClearSelected();
NewSoundsBox.SelectedItem = ns;
TabControl.SelectedIndex = 1;
FeedbackBox.Clear();
});
private void CreateTmpDir()
{
if (!Directory.Exists(".-tmp"))
Directory.CreateDirectory(".-tmp");
}
private void ExportDatatable(string path)
{
var mi = new MusicInfos();
mi.Items.AddRange(MusicInfos.Items);
mi.Items.AddRange(AddedMusic.Select(_ => _.MusicInfo));
var ma = new MusicAttributes();
ma.Items.AddRange(MusicAttributes.Items);
ma.Items.AddRange(AddedMusic.Select(_ => _.MusicAttribute));
var mo = new MusicOrders();
mo.Items.AddRange(MusicOrders.Items);
mo.Items.AddRange(AddedMusic.Select(_ => _.MusicOrder));
var wl = new WordList();
wl.Items.AddRange(WordList.Items);
wl.Items.AddRange(AddedMusic.Select(_ => new List<Word>() { _.Word, _.WordSub, _.WordDetail }).SelectMany(_ => _));
var jmi = Json.Serialize(mi);
var jma = Json.Serialize(ma);
var jmo = Json.Serialize(mo);
var jwl = Json.Serialize(wl);
File.WriteAllText(Path.Combine(path,"musicinfo"), jmi);
File.WriteAllText(Path.Combine(path,"music_attribute"), jma);
File.WriteAllText(Path.Combine(path,"music_order"), jmo);
File.WriteAllText(Path.Combine(path, "wordlist"), jwl);
GZ.CompressToFile(Path.Combine(path,"musicinfo.bin"), jmi);
GZ.CompressToFile(Path.Combine(path, "music_attribute.bin"), jma);
GZ.CompressToFile(Path.Combine(path, "music_order.bin"), jmo);
GZ.CompressToFile(Path.Combine(path, "wordlist.bin"), jwl);
}
private void ExportNusBanks(string path)
{
foreach(var ns in AddedMusic)
{
File.WriteAllBytes(Path.Combine(path, $"song_{ns.Id}.nus3bank"), ns.Nus3Bank);
}
}
private void ExportSoundBinaries(string path)
{
foreach (var ns in AddedMusic)
{
var sdir = Path.Combine(path, ns.Id);
if (!Directory.Exists(sdir))
Directory.CreateDirectory(sdir);
File.WriteAllBytes(Path.Combine(sdir, $"{ns.Id}_e.bin"), ns.EBin);
File.WriteAllBytes(Path.Combine(sdir, $"{ns.Id}_n.bin"), ns.NBin);
File.WriteAllBytes(Path.Combine(sdir, $"{ns.Id}_h.bin"), ns.HBin);
File.WriteAllBytes(Path.Combine(sdir, $"{ns.Id}_m.bin"), ns.MBin);
File.WriteAllBytes(Path.Combine(sdir, $"{ns.Id}_e_1.bin"), ns.EBin);
File.WriteAllBytes(Path.Combine(sdir, $"{ns.Id}_n_1.bin"), ns.NBin);
File.WriteAllBytes(Path.Combine(sdir, $"{ns.Id}_h_1.bin"), ns.HBin);
File.WriteAllBytes(Path.Combine(sdir, $"{ns.Id}_m_1.bin"), ns.MBin);
File.WriteAllBytes(Path.Combine(sdir, $"{ns.Id}_e_2.bin"), ns.EBin);
File.WriteAllBytes(Path.Combine(sdir, $"{ns.Id}_n_2.bin"), ns.NBin);
File.WriteAllBytes(Path.Combine(sdir, $"{ns.Id}_h_2.bin"), ns.HBin);
File.WriteAllBytes(Path.Combine(sdir, $"{ns.Id}_m_2.bin"), ns.MBin);
if(ns.MusicAttribute.CanPlayUra)
{
File.WriteAllBytes(Path.Combine(sdir, $"{ns.Id}_x.bin"), ns.XBin);
File.WriteAllBytes(Path.Combine(sdir, $"{ns.Id}_x_1.bin"), ns.XBin);
File.WriteAllBytes(Path.Combine(sdir, $"{ns.Id}_x_2.bin"), ns.XBin);
}
}
}
private void ExportDatatableButton_Click(object sender, EventArgs e) => RunGuard(() =>
{
var path = PickPath();
if (path == null)
{
MessageBox.Show("No path chosen. Operation canceled");
return;
}
ExportDatatable(path);
MessageBox.Show("Done");
if (ExportOpenOnFinished.Checked)
Process.Start($"explorer.exe", path);
});
private void ExportSoundFoldersButton_Click(object sender, EventArgs e) => RunGuard(() =>
{
var path = PickPath();
if (path == null)
{
MessageBox.Show("No path chosen. Operation canceled");
return;
}
ExportSoundBinaries(path);
MessageBox.Show("Done");
if (ExportOpenOnFinished.Checked)
Process.Start($"explorer.exe", path);
});
private void ExportSoundBanksButton_Click(object sender, EventArgs e) => RunGuard(() =>
{
var path = PickPath();
if (path == null)
{
MessageBox.Show("No path chosen. Operation canceled");
return;
}
ExportNusBanks(path);
MessageBox.Show("Done");
if (ExportOpenOnFinished.Checked)
Process.Start($"explorer.exe", path);
});
private string PickPath()
{
var picker = new FolderPicker();
if (picker.ShowDialog() == true)
return picker.ResultPath;
return null;
}
private void ExportAllButton_Click(object sender, EventArgs e) => RunGuard(() =>
{
var path = PickPath();
if (path == null)
{
MessageBox.Show("No path chosen. Operation canceled");
return;
}
var dtpath = Path.Combine(path, "datatable");
if (!Directory.Exists(dtpath)) Directory.CreateDirectory(dtpath);
var nupath = Path.Combine(path, "nus3banks");
if (!Directory.Exists(nupath)) Directory.CreateDirectory(nupath);
var sbpath = Path.Combine(path, "soundsbin");
if (!Directory.Exists(sbpath)) Directory.CreateDirectory(sbpath);
ExportDatatable(dtpath);
ExportSoundBinaries(sbpath);
ExportNusBanks(nupath);
MessageBox.Show("Done");
if (ExportOpenOnFinished.Checked)
Process.Start($"explorer.exe", path);
});
private void TJASelector_PathChanged(object sender, EventArgs args)
{
if (TJASelector.Path == null) return;
if (SongNameBox.Text != "" && SongNameBox.Text != "(6 characters id...)") return;
var name = Path.GetFileNameWithoutExtension(TJASelector.Path);
if (name.Length == 6)
SongNameBox.Text = name;
}
}
}

60
MainForm.resx Normal file
View File

@ -0,0 +1,60 @@
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

48
NUS3Bank.cs Normal file
View File

@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TaikoSoundEditor.Properties;
namespace TaikoSoundEditor
{
internal static class NUS3Bank
{
private static void Write32(byte[] b, int pos, uint x)
{
b[pos++] = (byte)(x & 0xFF); x >>= 8;
b[pos++] = (byte)(x & 0xFF); x >>= 8;
b[pos++] = (byte)(x & 0xFF); x >>= 8;
b[pos] = (byte)(x & 0xFF);
}
public static byte[] GetNus3Bank(string songId, int uniqueId, byte[] idsp, float demostart)
{
using var ms = new MemoryStream();
var header = Resources.song_ABCDEF_nus3bank.ToArray();
for(int i=0;i<6;i++)
{
header[0xAA + i] = (byte)songId[i];
header[0xD4E + i] = (byte)songId[i];
}
header[0xB4] = (byte)(uniqueId & 0xFF);
header[0xB5] = (byte)((uniqueId >> 8) & 0xFF);
Write32(header, 0x4C, (uint)idsp.Length);
Write32(header, 0xD64, (uint)idsp.Length);
Write32(header, 0xE1C, (uint)idsp.Length);
uint bb = (uint)(demostart * 1000);
Write32(header, 0xDDC, bb);
Write32(header, 0xDE4, bb);
ms.Write(header);
ms.Write(idsp);
return ms.ToArray();
}
}
}

31
Program.cs Normal file
View File

@ -0,0 +1,31 @@
using System.Diagnostics;
namespace TaikoSoundEditor
{
internal static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
/*var tja = new TJA(File.ReadAllLines($@"C:\Users\NotImpLife\Desktop\nus\EXAMPLE .TJA\hoshis\hoshis.tja"));
File.WriteAllText("tja.txt", tja.ToString());
for (int i = 0; i < 4; i++)
{
var c = tja.Courses[i].Converted;
Debug.WriteLine(i+" "+c.Notes.Length);
//Debug.WriteLine(c.Events.Length);
}
return;*/
//File.WriteAllText("tja.txt", tja.ToString());
ApplicationConfiguration.Initialize();
Application.Run(new MainForm());
}
}
}

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project>
<PropertyGroup>
<Configuration>Release</Configuration>
<Platform>Any CPU</Platform>
<PublishDir>bin\Release\net6.0-windows\publish\win-x86\</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<_TargetId>Folder</_TargetId>
<TargetFramework>net6.0-windows</TargetFramework>
<RuntimeIdentifier>win-x86</RuntimeIdentifier>
<SelfContained>true</SelfContained>
<PublishSingleFile>true</PublishSingleFile>
<PublishReadyToRun>true</PublishReadyToRun>
</PropertyGroup>
</Project>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project>
<PropertyGroup>
<History>True|2023-07-17T08:15:26.2194507Z;</History>
<LastFailureDetails />
</PropertyGroup>
</Project>

73
Properties/Resources.Designer.cs generated Normal file
View File

@ -0,0 +1,73 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace TaikoSoundEditor.Properties {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("TaikoSoundEditor.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] song_ABCDEF_nus3bank {
get {
object obj = ResourceManager.GetObject("song_ABCDEF_nus3bank", resourceCulture);
return ((byte[])(obj));
}
}
}
}

124
Properties/Resources.resx Normal file
View File

@ -0,0 +1,124 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="song_ABCDEF_nus3bank" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\song_ABCDEF_nus3bank.bin;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
</root>

Binary file not shown.

621
TJA.cs Normal file
View File

@ -0,0 +1,621 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using TaikoSoundEditor.Extensions;
using static TaikoSoundEditor.TJA;
namespace TaikoSoundEditor
{
internal class TJA
{
public TJA(string[] content)
{
Parse(content);
}
public class Line
{
public string Type { get; set; }
public string Scope { get; set; }
public string Name { get; set; }
public string Value { get; set; }
public Line(string type, string scope, string name, string value)
{
Type = type;
Scope = scope;
Name = name;
Value = value;
}
}
static readonly string[] HEADER_GLOBAL = new string[]
{
"TITLE", "SUBTITLE", "BPM", "WAVE", "OFFSET", "DEMOSTART","GENRE",
};
static readonly string[] HEADER_COURSE = new string[]
{
"COURSE", "LEVEL", "BALLOON", "SCOREINIT", "SCOREDIFF", "TTROWBEAT",
};
static readonly string[] COMMAND = new string[]
{
"START","END","GOGOSTART","GOGOEND","MEASURE","SCROLL","BPMCHANGE","DELAY","BRANCHSTART","BRANCHEND","SECTION","N","E","M","LEVELHOLD","BMSCROLL","HBSCROLL","BARLINEOFF","BARLINEON","TTBREAK",
};
public Line ParseLine(string line)
{
Match match = null;
Debug.WriteLine(line);
if ((match = line.Match("\\/\\/.*")) != null)
{
line = line.Substring(0, match.Index).Trim();
}
if ((match = line.Match("^([A-Z]+):(.+)", "i")) != null)
{
var nameUpper = match.Groups[1].Value.ToUpper();
var value = match.Groups[2].Value;
Debug.WriteLine($"Match = {nameUpper}, {value}");
if (HEADER_GLOBAL.Contains(nameUpper))
{
Debug.WriteLine("Header++");
return new Line("header", "global", nameUpper, value.Trim());
}
else if (HEADER_COURSE.Contains(nameUpper))
{
Debug.WriteLine("HCourse++");
return new Line("header", "course", nameUpper, value.Trim());
}
}
else if ((match = line.Match("^#([A-Z]+)(?:\\s+(.+))?", "i")) != null)
{
var nameUpper = match.Groups[1].Value.ToUpper();
var value = match.Groups[2].Value ?? "";
if (COMMAND.Contains(nameUpper))
return new Line("command", null, nameUpper, value.Trim());
}
else if ((match = line.Match("^(([0-9]|A|B|C|F|G)*,?)$")) != null)
{
var data = match.Groups[1].Value;
return new Line("data", null, null, data);
}
return new Line("unknwon", null, null, line);
}
public Course GetCourse(Header tjaHeaders, Line[] lines)
{
var headers = new CourseHeader();
var measures = new List<Measure>();
var measureDividend = 4;
var measureDivisor = 4;
var measureProperties = new Dictionary<string, bool>();
var measureData = "";
var measureEvents = new List<MeasureEvent>();
var currentBranch = "N";
var targetBranch = "N";
var flagLevelhold = false;
foreach(var line in lines)
{
if(line.Type=="header")
{
if (line.Name == "COURSE")
headers.Course = line.Value;
else if (line.Name == "LEVEL")
headers.Level = int.Parse(line.Value);
else if (line.Name == "BALLOON")
headers.Balloon = new Regex("[^0-9]").Split(line.Value).Where(_ => _ != "").Select(int.Parse).ToArray();
else if (line.Name == "SCOREINIT")
headers.ScoreInit = int.Parse(line.Value);
else if (line.Name == "SCOREDIFF")
headers.ScoreDiff = int.Parse(line.Value);
else if (line.Name == "TTROWBEAT")
headers.TTRowBeat = int.Parse(line.Value);
}
else if(line.Type=="command")
{
if (line.Name == "BRANCHSTART")
{
if (!flagLevelhold)
{
var values = line.Value.Split(',');
if (values[0] == "r")
{
if (values.Length >= 3) targetBranch = "M";
else if (values.Length == 2) targetBranch = "E";
else targetBranch = "N";
}
else if (values[0] == "p")
{
if (values.Length >= 3 && float.Parse(values[2]) <= 100) targetBranch = "M";
else if (values.Length >= 2 && float.Parse(values[1]) <= 100) targetBranch = "E";
else targetBranch = "N";
}
}
}
else if (line.Name == "BRANCHEND")
currentBranch = targetBranch;
else if (line.Name == "N" || line.Name == "E" || line.Name == "M")
currentBranch = line.Name;
else if(line.Name=="START" || line.Name == "END")
{
currentBranch = targetBranch = "N";
flagLevelhold = false;
}
else
{
if (currentBranch == targetBranch)
{
if (line.Name == "MEASURE")
{
var matchMeasure = line.Value.Match("(\\d+)\\/(\\d+)");
if (matchMeasure != null)
{
measureDividend = int.Parse(matchMeasure.Groups[1].Value);
measureDivisor = int.Parse(matchMeasure.Groups[2].Value);
}
}
else if (line.Name == "GOGOSTART")
measureEvents.Add(new MeasureEvent("gogoStart", measureData.Length));
else if (line.Name == "GOGOEND")
measureEvents.Add(new MeasureEvent("gogoEnd", measureData.Length));
else if (line.Name == "SCROLL")
measureEvents.Add(new MeasureEvent("scroll", measureData.Length, float.Parse(line.Value)));
else if (line.Name == "BPMCHANGE")
measureEvents.Add(new MeasureEvent("bpm", measureData.Length, float.Parse(line.Value)));
else if (line.Name == "TTBREAK")
measureProperties["ttBreak"] = true;
else if (line.Name == "LEVELHOLD")
flagLevelhold = true;
}
}
}
else if(line.Type=="data" && currentBranch==targetBranch)
{
var data = line.Value;
if (data.EndsWith(","))
{
measureData += data.Substring(0, data.Length - 1); //data.slice(0, -1);
var measure = new Measure(new int[] { measureDividend, measureDivisor }, measureProperties, measureData, measureEvents.ToList());
measures.Add(measure);
measureData = "";
measureEvents.Clear();
measureProperties.Clear();
}
else measureData += data;
}
} // foreach
if(measures.Count>0)
{
// Make first BPM event
var firstBPMEventFound = false;
for (var i = 0; i < measures[0].Events.Count; i++)
{
var evt = measures[0].Events[i];
if (evt.Name == "bpm" && evt.Position == 0)
{
firstBPMEventFound = true;
break;
}
}
if (!firstBPMEventFound)
{
measures[0].Events = measures[0].Events.Prepend(new MeasureEvent("bmp", 0, tjaHeaders.Bpm)).ToList();
}
}
// Helper values
var course = 0;
var courseValue = headers.Course.ToLower();
if (courseValue == "easy" || courseValue == "0")
course = 0;
else if (courseValue == "normal" || courseValue == "1")
course = 1;
else if (courseValue == "hard" || courseValue == "2")
course = 2;
else if(courseValue=="oni" || courseValue=="3")
course = 3;
else if (courseValue == "edit" || courseValue == "ura"|| courseValue == "4")
course = 4;
if(measureData!="" || measureData!=null)
{
measures.Add(new Measure(new int[] { measureDividend, measureDivisor }, measureProperties, measureData, measureEvents));
}
else
{
foreach(var ev in measureEvents)
{
ev.Position = measures[measures.Count - 1].MeasureData.Length;
measures[measures.Count - 1].Events.Add(ev);
}
}
Debug.WriteLine(measures[measures.Count - 1]);
return new Course(course, headers, measures);
}
public void Parse(string[] lines)
{
var headers = new Header();
var courses = new Dictionary<int, Course>();
int idx;
var courseLines = new List<Line>();
for(idx=0;idx<lines.Length;idx++)
{
var line = lines[idx];
if (line == "") continue;
var parsed = ParseLine(line);
if(parsed.Type=="header" && parsed.Scope=="global")
{
if (parsed.Name == "TITLE")
headers.Title = parsed.Value;
if (parsed.Name == "SUBTITLE")
headers.Subtitle = parsed.Value;
if (parsed.Name == "BPM")
headers.Bpm = float.Parse(parsed.Value);
if (parsed.Name == "WAVE")
headers.Wave = parsed.Value;
if (parsed.Name == "OFFSET")
headers.Offset = float.Parse(parsed.Value);
if (parsed.Name == "DEMOSTART")
headers.DemoStart = float.Parse(parsed.Value);
if (parsed.Name == "GENRE")
headers.Genre = parsed.Value;
}
else if (parsed.Type == "header" && parsed.Scope == "course")
{
if (parsed.Name == "COURSE")
{
Debug.WriteLine($"Course found : {parsed.Value}");
if (courseLines.Count>0)
{
var course = GetCourse(headers, courseLines.ToArray());
courses[course.CourseN] = course;
courseLines.Clear();
}
}
courseLines.Add(parsed);
}
else
courseLines.Add(parsed);
}
if(courseLines.Count>0)
{
var course = GetCourse(headers, courseLines.ToArray());
courses[course.CourseN] = course;
}
Headers = headers;
Courses = courses;
}
public Header Headers;
public Dictionary<int, Course> Courses;
public class Course
{
public int CourseN { get; set; }
public CourseHeader Headers { get; set; }
public List<Measure> Measures { get; set; }
public Course(int courseN, CourseHeader headers, List<Measure> measures)
{
CourseN = courseN;
Headers = headers;
Measures = measures;
}
public override string ToString()
=> $"C({CourseN},{Headers},{string.Join("|",Measures)})";
public ConvertedCourse Converted => ConvertToTimes(this);
}
public class Measure
{
public int[] Length { get; set; }
public Dictionary<string, bool> Properties { get; set; }
public string MeasureData { get; set; }
public List<MeasureEvent> Events { get; set; }
public Measure(int[] length, Dictionary<string, bool> properties, string measureData, List<MeasureEvent> events)
{
Length = length;
Properties = properties;
MeasureData = measureData;
Events = events;
}
public override string ToString() =>
$"M({string.Join(" ", Length)},{string.Join(";", Properties.Select(kv => kv.Key + "=" + kv.Value))},{MeasureData},{string.Join(";", Events)})";
}
public class MeasureEvent
{
public string Name { get; set; }
public int Position { get; set; }
public float Value { get; set; }
public MeasureEvent(string name, int position, float value = 0)
{
Name = name;
Position = position;
Value = value;
}
public override string ToString() => $"ME({Name},{Position},{Value}";
}
public class Header
{
public string Title { get; set; } = "";
public string Subtitle { get; set; } = "";
public float Bpm { get; set; } = 120;
public string Wave { get; set; } = "";
public float Offset { get; set; } = 0;
public float DemoStart { get; set; } = 0;
public string Genre { get; set; } = "";
public override string ToString() => $"H({Title},{Subtitle},{Bpm},{Wave},{Offset},{DemoStart},{Genre})";
}
public class CourseHeader
{
public string Course { get; set; } = "Oni";
public int Level { get; set; } = 0;
public int[] Balloon { get; set; } = new int[0];
public int ScoreInit { get; set; } = 100;
public int ScoreDiff { get; set; } = 100;
public int TTRowBeat { get; set; } = 16;
public override string ToString() => $"CH({Course}, {Level}, {string.Join(";",Balloon)}, {ScoreInit}, {ScoreDiff}, {TTRowBeat})";
}
public static List<byte[]> RunTja2Fumen(string sourcePath)
{
sourcePath = Path.GetFullPath(sourcePath);
var dir = Path.GetDirectoryName(sourcePath);
var fname = Path.GetFileNameWithoutExtension(sourcePath);
var p = new Process();
p.StartInfo.FileName = Path.GetFullPath(@"Tools\tja2fumen.exe");
p.StartInfo.ArgumentList.Add(sourcePath);
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.RedirectStandardOutput = true;
p.Start();
p.WaitForExit();
int exitCode = p.ExitCode;
string stdout = p.StandardOutput.ReadToEnd();
string stderr = p.StandardError.ReadToEnd();
if (exitCode != 0)
throw new Exception($"Process tja2fumen failed with exit code {exitCode}:\n" + stderr);
var result = new List<byte[]>
{
File.ReadAllBytes(Path.Combine(dir, fname + "_e.bin")),
File.ReadAllBytes(Path.Combine(dir, fname + "_h.bin")),
File.ReadAllBytes(Path.Combine(dir, fname + "_m.bin")),
File.ReadAllBytes(Path.Combine(dir, fname + "_n.bin"))
};
File.Delete(Path.Combine(dir, fname + "_e.bin"));
File.Delete(Path.Combine(dir, fname + "_h.bin"));
File.Delete(Path.Combine(dir, fname + "_m.bin"));
File.Delete(Path.Combine(dir, fname + "_n.bin"));
if (File.Exists(Path.Combine(dir, fname + "_x.bin")))
{
result.Add(File.ReadAllBytes(Path.Combine(dir, fname + "_x.bin")));
File.Delete(Path.Combine(dir, fname + "_x.bin"));
}
return result;
}
public override string ToString() => $"{Headers}\n{string.Join("\n", Courses)}";
public static ConvertedCourse ConvertToTimes(Course course)
{
List<TimedEvent> events=new List<TimedEvent>();
List<Note> notes = new List<Note>();
float beat = 0;
int balloon=0;
bool imo = false;
for (int m = 0; m < course.Measures.Count; m++)
{
var measure = course.Measures[m];
float length = measure.Length[0] / measure.Length[1] * 4;
for (int e = 0; e < measure.Events.Count; e++)
{
var evt = measure.Events[e];
float eBeat = length / (measure.MeasureData.Length == 0 ? 1 : measure.MeasureData.Length) * evt.Position;
if (evt.Name == "bpm")
events.Add(new TimedEvent("bmp", evt.Value, beat + eBeat));
else if (evt.Name == "gogoStart" || evt.Name == "gogoEnd")
events.Add(new TimedEvent(evt.Name, 0, beat + eBeat));
}
for(int d=0;d<measure.MeasureData.Length;d++)
{
var ch = measure.MeasureData[d];
var nBeat = length / measure.MeasureData.Length * d;
var note = new Note("", beat + nBeat);
switch(ch)
{
case '1':
note.Type = "don";
break;
case '2':
note.Type = "kat";
break;
case '3':
case 'A':
note.Type = "donBig";
break;
case '4':
case 'B':
note.Type = "katBig";
break;
case '5':
note.Type = "renda";
break;
case '6':
note.Type = "rendaBig";
break;
case '7':
note.Type = "balloon";
note.Count = course.Headers.Balloon[balloon++];
break;
case '8':
note.Type = "end";
if (imo) imo = false;
break;
case '9':
if (imo == false)
{
note.Type = "balloon";
note.Count = course.Headers.Balloon[balloon++];
imo = true;
}
break;
default: break;
}
if (note.Type != "") notes.Add(note);
}
beat += length;
}
var times = PulseToTime(events, notes.Select(n => n.Beat).ToArray());
for(int i=0;i<times.Length;i++)
{
notes[i].Time = times[i];
}
return new ConvertedCourse(course.Headers, events.ToArray(), notes.ToArray());
}
public class ConvertedCourse
{
public CourseHeader Headers { get; set; }
public TimedEvent[] Events { get; set; }
public Note[] Notes { get; set; }
public ConvertedCourse(CourseHeader headers, TimedEvent[] events, Note[] notes)
{
Headers = headers;
Events = events;
Notes = notes;
}
}
private static float[] PulseToTime(List<TimedEvent> events, float[] objects)
{
float bpm = 120;
float passedBeat = 0;
float passedTime = 0;
int eidx = 0, oidx = 0;
var times = new List<float>();
while(oidx<objects.Length)
{
var evt = eidx < events.Count ? events[eidx] : null;
var objBeat = objects[oidx];
while (evt != null && evt.Beat <= objBeat)
{
if (evt.Type == "bpm")
{
var _beat = evt.Beat - passedBeat;
var _time = 60 / bpm * _beat;
passedBeat += _beat;
passedTime += _time;
bpm = evt.Value;
}
eidx++;
evt = eidx < events.Count ? events[eidx] : null;
}
var beat = objBeat - passedBeat;
var time = 60 / bpm * beat;
times.Add(passedTime + time);
passedBeat += beat;
passedTime += time;
oidx++;
}
return times.ToArray();
}
public class TimedEvent
{
public string Type { get; set; }
public float Value { get; set; }
public float Beat { get; set; }
public TimedEvent(string type, float value, float beat)
{
Type = type;
Value = value;
Beat = beat;
}
}
public class Note
{
public string Type { get; set; }
public float Beat { get; set; }
public int Count { get; set; }
public float Time { get; set; }
public Note(string type, float beat)
{
Type = type;
Beat = beat;
}
}
}
}

137
TaikoSoundEditor.csproj Normal file
View File

@ -0,0 +1,137 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net6.0-windows</TargetFramework>
<Nullable>disable</Nullable>
<UseWindowsForms>true</UseWindowsForms>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<Compile Update="Properties\Resources.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<None Update="Tools\sox\batch-example.bat">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Tools\sox\ChangeLog.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Tools\sox\libflac-8.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Tools\sox\libgcc_s_sjlj-1.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Tools\sox\libgomp-1.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Tools\sox\libid3tag-0.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Tools\sox\libogg-0.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Tools\sox\libpng16-16.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Tools\sox\libsox-3.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Tools\sox\libssp-0.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Tools\sox\libvorbis-0.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Tools\sox\libvorbisenc-2.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Tools\sox\libvorbisfile-3.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Tools\sox\libwavpack-1.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Tools\sox\libwinpthread-1.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Tools\sox\LICENSE.GPL.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Tools\sox\README.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Tools\sox\README.win32.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Tools\sox\sox.exe">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Tools\sox\sox.pdf">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Tools\sox\soxformat.pdf">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Tools\sox\soxi.pdf">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Tools\sox\wget.exe">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Tools\sox\wget.ini">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Tools\sox\zlib1.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Tools\tja2fumen.exe">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Tools\VGAudio\idsp\empty.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Tools\VGAudio\VGAudio.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Tools\VGAudio\VGAudio.pdb">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Tools\VGAudio\VGAudio.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Tools\VGAudio\VGAudioCli.exe">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Tools\VGAudio\VGAudioCli.pdb">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Tools\VGAudio\VGAudioTools.exe">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Tools\VGAudio\VGAudioTools.pdb">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Tools\VGAudio\wav2idsp.bat">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Tools\VGAudio\wav\empty.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

BIN
Tools/VGAudio/VGAudio.dll Normal file

Binary file not shown.

BIN
Tools/VGAudio/VGAudio.pdb Normal file

Binary file not shown.

1007
Tools/VGAudio/VGAudio.xml Normal file

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

View File

View File

@ -0,0 +1,2 @@
VGAudioCli.exe -b -i wav -o idsp --out-format idsp
@pause

1759
Tools/sox/ChangeLog.txt Normal file

File diff suppressed because it is too large Load Diff

339
Tools/sox/LICENSE.GPL.txt Normal file
View File

@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

196
Tools/sox/README.txt Normal file
View File

@ -0,0 +1,196 @@
SoX: Sound eXchange
===================
SoX (Sound eXchange) is the Swiss Army knife of sound processing tools: it
can convert sound files between many different file formats & audio devices,
and can apply many sound effects & transformations, as well as doing basic
analysis and providing input to more capable analysis and plotting tools.
SoX is licensed under the GNU GPL and GNU LGPL. To be precise, the 'sox'
and 'soxi' programs are distributed under the GPL, while the library
'libsox' (in which most of SoX's functionality resides) is dual-licensed.
Note that some optional components of libsox are GPL only: if you use these,
you must use libsox under the GPL. See INSTALL for the list of optional
components and their licences.
If this distribution is of source code (as opposed to pre-built binaries),
then you will need to compile and install SoX as described in the 'INSTALL'
file.
Changes between this release and previous releases of SoX can be found in
the 'ChangeLog' file; a summary of the file formats and effects supported in
this release can be found below. Detailed documentation for using SoX can
be found in the distributed 'man' pages:
o sox(1)
o soxi(1)
o soxformat(7)
o libsox(3)
or in plain text or PDF files for those systems without man.
The majority of SoX features and fixes are contributed by SoX users - thank
you very much for making SoX a success! There are several new features
wanted for SoX, listed on the feature request tracker at the SoX project
home-page:
http://sourceforge.net/projects/sox
users are encouraged to implement them!
Please submit bug reports, new feature requests, and patches to the relevant
tracker at the above address, or by email:
mailto:sox-devel@lists.sourceforge.net
Also accessible via the project home-page is the SoX users' discussion
mailing list which you can join to discuss all matters SoX with other SoX
users; the mail address for this list is:
mailto:sox-users@lists.sourceforge.net
The current release handles the following audio file formats:
o Raw files in various binary formats
o Raw textual data
o Amiga 8svx files
o Apple/SGI AIFF files
o SUN .au files
o PCM, u-law, A-law
o G7xx ADPCM files (read only)
o mutant DEC .au files
o NeXT .snd files
o AVR files
o CDDA (Compact Disc Digital Audio format)
o CVS and VMS files (continuous variable slope)
o Grandstream ring-tone files
o GSM files
o HTK files
o LPC-10 files
o Macintosh HCOM files
o Amiga MAUD files
o AMR-WB & AMR-NB (with optional libamrwb & libamrnb libraries)
o MP2/MP3 (with optional libmad, libtwolame and libmp3lame libraries)
o Opus files (read only; with optional Opus libraries)
o Ogg Vorbis files (with optional Ogg Vorbis libraries)
o FLAC files (with optional libFLAC)
o IRCAM SoundFile files
o NIST SPHERE files
o Turtle beach SampleVision files
o Sounder & Soundtool (DOS) files
o Yamaha TX-16W sampler files
o SoundBlaster .VOC files
o Dialogic/OKI ADPCM files (.VOX)
o Microsoft .WAV files
o PCM, floating point
o u-law, A-law, MS ADPCM, IMA (DMI) ADPCM
o GSM
o RIFX (big endian)
o WavPack files (with optional libwavpack library)
o Psion (palmtop) A-law WVE files and Record voice notes
o Maxis XA Audio files
o EA ADPCM (read support only, for now)
o Pseudo formats that allow direct playing/recording from most audio devices
o The "null" pseudo-file that reads and writes from/to nowhere
The audio effects/tools included in this release are as follows:
o Tone/filter effects
o allpass: RBJ all-pass biquad IIR filter
o bandpass: RBJ band-pass biquad IIR filter
o bandreject: RBJ band-reject biquad IIR filter
o band: SPKit resonator band-pass IIR filter
o bass: Tone control: RBJ shelving biquad IIR filter
o equalizer: RBJ peaking equalisation biquad IIR filter
o firfit+: FFT convolution FIR filter using given freq. response (W.I.P.)
o highpass: High-pass filter: Single pole or RBJ biquad IIR
o hilbert: Hilbert transform filter (90 degrees phase shift)
o lowpass: Low-pass filter: single pole or RBJ biquad IIR
o sinc: Sinc-windowed low/high-pass/band-pass/reject FIR
o treble: Tone control: RBJ shelving biquad IIR filter
o Production effects
o chorus: Make a single instrument sound like many
o delay: Delay one or more channels
o echo: Add an echo
o echos: Add a sequence of echos
o flanger: Stereo flanger
o overdrive: Non-linear distortion
o phaser: Phase shifter
o repeat: Loop the audio a number of times
o reverb: Add reverberation
o reverse: Reverse the audio (to search for Satanic messages ;-)
o tremolo: Sinusoidal volume modulation
o Volume/level effects
o compand: Signal level compression/expansion/limiting
o contrast: Phase contrast volume enhancement
o dcshift: Apply or remove DC offset
o fade: Apply a fade-in and/or fade-out to the audio
o gain: Apply gain or attenuation; normalise/equalise/balance/headroom
o loudness: Gain control with ISO 226 loudness compensation
o mcompand: Multi-band compression/expansion/limiting
o norm: Normalise to 0dB (or other)
o vol: Adjust audio volume
o Editing effects
o pad: Pad (usually) the ends of the audio with silence
o silence: Remove portions of silence from the audio
o splice: Perform the equivalent of a cross-faded tape splice
o trim: Cuts portions out of the audio
o vad: Voice activity detector
o Mixing effects
o channels: Auto mix or duplicate to change number of channels
o divide+: Divide sample values by those in the 1st channel (W.I.P.)
o remix: Produce arbitrarily mixed output channels
o swap: Swap pairs of channels
o Pitch/tempo effects
o bend: Bend pitch at given times without changing tempo
o pitch: Adjust pitch (= key) without changing tempo
o speed: Adjust pitch & tempo together
o stretch: Adjust tempo without changing pitch (simple alg.)
o tempo: Adjust tempo without changing pitch (WSOLA alg.)
o Mastering effects
o dither: Add dither noise to increase quantisation SNR
o rate: Change audio sampling rate
o Specialised filters/mixers
o deemph: ISO 908 CD de-emphasis (shelving) IIR filter
o earwax: Process CD audio to best effect for headphone use
o noisered: Filter out noise from the audio
o oops: Out Of Phase Stereo (or `Karaoke') effect
o riaa: RIAA vinyl playback equalisation
o Analysis `effects'
o noiseprof: Produce a DFT profile of the audio (use with noisered)
o spectrogram: graph signal level vs. frequency & time (needs `libpng')
o stat: Enumerate audio peak & RMS levels, approx. freq., etc.
o stats: Multichannel aware `stat'
o Miscellaneous effects
o ladspa: Apply LADSPA plug-in effects e.g. CMT (Computer Music Toolkit)
o synth: Synthesise/modulate audio tones or noise signals
o newfile: Create a new output file when an effects chain ends.
o restart: Restart 1st effects chain when multiple chains exist.
o Low-level signal processing effects
o biquad: 2nd-order IIR filter using externally provided coefficients
o downsample: Reduce sample rate by discarding samples
o fir: FFT convolution FIR filter using externally provided coefficients
o upsample: Increase sample rate by zero stuffing
+ Experimental or incomplete effect; may change in future.
Multiple audio files can be combined (and then further processed with
effects) using any one of the following combiner methods:
o concatenate
o mix
o merge: E.g. two mono files to one stereo file
o sequence: For playing multiple audio files/streams

167
Tools/sox/README.win32.txt Normal file
View File

@ -0,0 +1,167 @@
SoX
---
This file contains information specific to the Win32 version of SoX.
Please refer to the README file for general information.
The binary SOX.EXE can be installed anywhere you desire. The only
restriction is that the included ZLIB1..DLL and LIBGOMP-1.DLL must be
located in the same directory as SOX.EXE or somewhere within your PATH.
SoX Helper Applications
-----------------------
SoX also includes support for SOXI.EXE, PLAY.EXE and REC.EXE and their
behaviors are documented in included PDF's. They have the same
install restrictions as SOX.EXE.
SOXI.EXE, PLAY.EXE, and REC.EXE are not distributed with this package to
reduce size requirements. They are, in fact, only copies of the original
SOX.EXE binary which changes SOX.EXE's behavior based on the
executable's filename.
If you wish to make use of these utils then you can create them
yourself.
copy sox.exe soxi.exe
copy sox.exe play.exe
copy sox.exe rec.exe
If you are concerned with disk space, the play and record
functionality can be equated using the "-d" option with SOX.EXE. soxi
functionality can be equated using the "--info" option with SOX.EXE. The
rough syntax is:
play: sox [input files and options] -d [effects]
rec: sox -d [output file and options] [effects]
soxi: sox --info [input files and options]
Acknowledgements
----------------
SOX.EXE included in this package makes use of the following projects.
See the cygbuild script included with the source code package for
further information on how it was compiled and packaged.
SoX - http://sox.sourceforge.net
FLAC - http://flac.sourceforge.net
LADSPA - http://www.ladspa.org
libid3tag - http://www.underbit.com/products/mad
libsndfile - http://www.mega-nerd.com/libsndfile
Ogg Vorbis - http://www.vorbis.com
PNG - http://www.libpng.org/pub/png
WavPack - http://www.wavpack.com
wget - http://www.gnu.org/software/wget
Enjoy,
The SoX Development Team
Appendix - wget Support
-----------------------
SoX can make use of the wget command line utility to load files over
the internet. A binary copy of wget has been included with this
package of SoX for your convience.
For SoX to make use of wget, it must be located either in your PATH or
within the same directory that SoX is ran from.
Custom configuration of wget can be made by editing the file wget.ini
contained in the same directory as wget.exe.
Please consult wget's homepage for access to source code as well as
further instructions on configuring.
http://www.gnu.org/software/wget
Appendix - MP3 Support
----------------------
SoX contains support for reading and writing MP3 files but does not ship
with the DLL's that perform decoding and encoding of MP3 data because
of patent restrictions. For further details, refer to:
http://en.wikipedia.org/wiki/MP3#Licensing_and_patent_issues
MP3 support can be enabled by placing Lame encoding DLL and/or
MAD decoding DLL into the same directory as SOX.EXE. These
can be compiled yourself, they may turn up on searches of the internet
or may be included with other MP3 applications already installed
on your system. For encoding/writing, try searching for lame-enc.dll,
libmp3lame-0.dll, libmp3lame.dll, or cygmp3lame-0.dll. For
decoding/reading, try searching for libmad-0.dll, libmad.dll or cygmad-0.dll.
Instructions are included here for using MSYS to create the DLL's.
It is assumed you already have MSYS installed on your system
with a working gcc compiler. The commands are ran from MSYS
bash shell.
Obtain the latest Lame and MAD source code from approprate locations.
Lame MP3 encoder http://lame.sourceforge.net
MAD MP3 decoder http://www.underbit.com/products/mad
cd lame-398-2
./configure --disabled-static --enable-shared
make
cp libmp3lame/.libs/libmp3lame-0.dll /path/to/sox
MAD libraries up to 0.15.1b have a bug in configure that will not allow
building DLL under mingw. This can be resolved by adding LDFLAGS
to configure and editing the generated Makefile to remove an invalid
option.
cd libmad-0.15.1b
./configure --enable-shared --disable-static LDFLAGS="-no-undefined"
[edit Makefile, search for "-fforce-mem" and delete it.]
make
cp libmad-0.dll /path/to/sox/
Appendix - AMR-NB/AMR-WB Support
--------------------------------
SoX contains support for reading and writing AMR-NB and AMR-WB files but
does not ship with the DLL's that perform decoding and encoding of AMR
data because of patent restrictions.
AMR-NB/AMR-WB support can be enabled by placing required DLL's
into the same directory as SOX.EXE. These can be compiled yourself,
they may turn up on searches of the internet or may be included with other
MP3 applications already installed on your system. For AMR-NB support,
try searching for libamrnb-3.dll, libopencore-amrnb-0.dll, or
libopencore-amrnb.dll. For AMR-WB support, try searching for libamrwb-3.dll,
libopencore-amrwb-0.dll, or libopencore-amrwb.dll.
Instructions are included here for using MSYS to create the DLL's.
It is assumed you already have MSYS installed on your system with
working gcc compiler. These commands are ran from MSYS bash shell.
Obtain the latest amrnb and amrwb source code from
http://sourceforge.net/projects/opencore-amr .
cd opencore-amr-0.1.2
./configure --enable-shared --disable-static LDFLAGS="-no-undefined"
make
cp amrnb/.libs/libopencore-amrnb-0.dll /path/to/sox
cp amrwb/.libs/libopencore-amrwb-0.dll /path/to/sox
Appendix - LADSPA Plugins
-------------------------
SoX has built in support for LADSPA Plugins. These plugins are
mostly built for Linux but some are available for Windows.
The Audacity GUI application has a page that points to a collection
of Windows LADSPA plugins.
http://audacity.sourceforge.net/download/plugins
SoX will search for these plugins based on LADSPA_PATH
enviornment variable. See sox.txt for further information.

View File

@ -0,0 +1,14 @@
rem Example of how to do batch processing with SoX on MS-Windows.
rem
rem Place this file in the same folder as sox.exe (& rename it as appropriate).
rem You can then drag and drop a selection of files onto the batch file (or
rem onto a `short-cut' to it).
rem
rem In this example, the converted files end up in a folder called `converted',
rem but this, of course, can be changed, as can the parameters to the sox
rem command.
cd %~dp0
mkdir converted
FOR %%A IN (%*) DO sox %%A "converted/%%~nxA" rate -v 44100
pause

BIN
Tools/sox/libflac-8.dll Normal file

Binary file not shown.

Binary file not shown.

BIN
Tools/sox/libgomp-1.dll Normal file

Binary file not shown.

BIN
Tools/sox/libid3tag-0.dll Normal file

Binary file not shown.

BIN
Tools/sox/libogg-0.dll Normal file

Binary file not shown.

BIN
Tools/sox/libpng16-16.dll Normal file

Binary file not shown.

BIN
Tools/sox/libsox-3.dll Normal file

Binary file not shown.

BIN
Tools/sox/libssp-0.dll Normal file

Binary file not shown.

BIN
Tools/sox/libvorbis-0.dll Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
Tools/sox/libwavpack-1.dll Normal file

Binary file not shown.

Binary file not shown.

BIN
Tools/sox/sox.exe Normal file

Binary file not shown.

BIN
Tools/sox/sox.pdf Normal file

Binary file not shown.

BIN
Tools/sox/soxformat.pdf Normal file

Binary file not shown.

BIN
Tools/sox/soxi.pdf Normal file

Binary file not shown.

BIN
Tools/sox/wget.exe Normal file

Binary file not shown.

112
Tools/sox/wget.ini Normal file
View File

@ -0,0 +1,112 @@
###
### Sample Wget initialization file .wgetrc
###
## You can use this file to change the default behaviour of wget or to
## avoid having to type many many command-line options. This file does
## not contain a comprehensive list of commands -- look at the manual
## to find out what you can put into this file.
##
## Wget initialization file can reside in /usr/local/etc/wgetrc
## (global, for all users) or $HOME/.wgetrc (for a single user).
##
## To use the settings in this file, you will have to uncomment them,
## as well as change them, in most cases, as the values on the
## commented-out lines are the default values (e.g. "off").
##
## Global settings (useful for setting up in /usr/local/etc/wgetrc).
## Think well before you change them, since they may reduce wget's
## functionality, and make it behave contrary to the documentation:
##
# You can set retrieve quota for beginners by specifying a value
# optionally followed by 'K' (kilobytes) or 'M' (megabytes). The
# default quota is unlimited.
#quota = inf
# You can lower (or raise) the default number of retries when
# downloading a file (default is 20).
#tries = 20
# Lowering the maximum depth of the recursive retrieval is handy to
# prevent newbies from going too "deep" when they unwittingly start
# the recursive retrieval. The default is 5.
#reclevel = 5
# By default Wget uses "passive FTP" transfer where the client
# initiates the data connection to the server rather than the other
# way around. That is required on systems behind NAT where the client
# computer cannot be easily reached from the Internet. However, some
# firewalls software explicitly supports active FTP and in fact has
# problems supporting passive transfer. If you are in such
# environment, use "passive_ftp = off" to revert to active FTP.
#passive_ftp = off
# The "wait" command below makes Wget wait between every connection.
# If, instead, you want Wget to wait only between retries of failed
# downloads, set waitretry to maximum number of seconds to wait (Wget
# will use "linear backoff", waiting 1 second after the first failure
# on a file, 2 seconds after the second failure, etc. up to this max).
waitretry = 10
##
## Local settings (for a user to set in his $HOME/.wgetrc). It is
## *highly* undesirable to put these settings in the global file, since
## they are potentially dangerous to "normal" users.
##
## Even when setting up your own ~/.wgetrc, you should know what you
## are doing before doing so.
##
# Set this to on to use timestamping by default:
#timestamping = off
# It is a good idea to make Wget send your email address in a `From:'
# header with your request (so that server administrators can contact
# you in case of errors). Wget does *not* send `From:' by default.
#header = From: Your Name <username@site.domain>
# You can set up other headers, like Accept-Language. Accept-Language
# is *not* sent by default.
#header = Accept-Language: en
# You can set the default proxies for Wget to use for http and ftp.
# They will override the value in the environment.
#http_proxy = http://proxy.yoyodyne.com:18023/
#ftp_proxy = http://proxy.yoyodyne.com:18023/
# If you do not want to use proxy at all, set this to off.
#use_proxy = on
# You can customize the retrieval outlook. Valid options are default,
# binary, mega and micro.
#dot_style = default
# Setting this to off makes Wget not download /robots.txt. Be sure to
# know *exactly* what /robots.txt is and how it is used before changing
# the default!
#robots = on
# It can be useful to make Wget wait between connections. Set this to
# the number of seconds you want Wget to wait.
#wait = 0
# You can force creating directory structure, even if a single is being
# retrieved, by setting this to on.
#dirstruct = off
# You can turn on recursive retrieving by default (don't do this if
# you are not sure you know what it means) by setting this to on.
#recursive = off
# To always back up file X as X.orig before converting its links (due
# to -k / --convert-links / convert_links = on having been specified),
# set this variable to on:
#backup_converted = off
# To have Wget follow FTP links from HTML files by default, set this
# to on:
#follow_ftp = off

BIN
Tools/sox/zlib1.dll Normal file

Binary file not shown.

BIN
Tools/tja2fumen.exe Normal file

Binary file not shown.

37
WAV.cs Normal file
View File

@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TaikoSoundEditor
{
internal static class WAV
{
public static void ConvertToWav(string sourcePath, string destPath)
{
sourcePath = Path.GetFullPath(sourcePath);
destPath = Path.GetFullPath(destPath);
var p = new Process();
p.StartInfo.FileName = Path.GetFullPath(@"Tools\sox\sox.exe");
p.StartInfo.ArgumentList.Add(sourcePath);
p.StartInfo.ArgumentList.Add(destPath);
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.RedirectStandardOutput = true;
p.Start();
p.WaitForExit();
int exitCode = p.ExitCode;
string stdout = p.StandardOutput.ReadToEnd();
string stderr = p.StandardError.ReadToEnd();
if (exitCode != 0)
throw new Exception($"Process sox failed with exit code {exitCode}:\n" + stderr);
}
}
}