diff --git a/Assets/Editor/OpenTS2.meta b/Assets/Editor/OpenTS2.meta new file mode 100644 index 00000000..86354c85 --- /dev/null +++ b/Assets/Editor/OpenTS2.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9df48c8fa5a6cab4e9f09f360470982b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Editor/OpenTS2/Engine.meta b/Assets/Editor/OpenTS2/Engine.meta new file mode 100644 index 00000000..c0e59c25 --- /dev/null +++ b/Assets/Editor/OpenTS2/Engine.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: aa8397b8e06949944bc92d9edf46918a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Editor/OpenTS2/Engine/Tests.meta b/Assets/Editor/OpenTS2/Engine/Tests.meta new file mode 100644 index 00000000..206cc067 --- /dev/null +++ b/Assets/Editor/OpenTS2/Engine/Tests.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 67867722fd708e84a9476a63e1aa0e2b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Editor/OpenTS2/Engine/Tests/LotLoadingTestEditor.cs b/Assets/Editor/OpenTS2/Engine/Tests/LotLoadingTestEditor.cs new file mode 100644 index 00000000..e5e2ef7a --- /dev/null +++ b/Assets/Editor/OpenTS2/Engine/Tests/LotLoadingTestEditor.cs @@ -0,0 +1,110 @@ +using OpenTS2.Engine.Tests; +using OpenTS2.Engine; +using OpenTS2.Files; +using OpenTS2.Scenes.Lot.State; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEditor; + +namespace OpenTS2.Engine.Tests +{ + [CustomEditor(typeof(LotLoadingTest))] + public class LotLoadingTestEditor : Editor + { + private string _cachedNhood = ""; + private List NhoodNames = new List() { "N001" }; + private List LotIds = new List() { 82 }; + + public LotLoadingTestEditor() + { + PopulateNhoodList(); + } + + private void PopulateNhoodList() + { + NhoodNames.Clear(); + + var nhoodFolderPath = Path.Combine(Filesystem.UserDataDirectory, $"Neighborhoods"); + + foreach (var nhood in Directory.GetDirectories(nhoodFolderPath)) + { + string filename = Path.GetFileName(nhood); + + if (filename.Length == 4) + { + NhoodNames.Add(filename); + } + } + } + + private void PopulateLotList(string nhood) + { + _cachedNhood = nhood; + var lotsFolderPath = Path.Combine(Filesystem.UserDataDirectory, $"Neighborhoods/{nhood}/Lots"); + + LotIds.Clear(); + + try + { + foreach (string file in Directory.GetFiles(lotsFolderPath)) + { + if (file.EndsWith(".package")) + { + int tIndex = file.LastIndexOf('t'); + int end = file.Length - ".package".Length; + string lotIdProbably = file.Substring(tIndex + 1, end - (tIndex + 1)); + + if (int.TryParse(lotIdProbably, out int lotId)) + { + LotIds.Add(lotId); + } + } + } + } + catch + { + + } + + LotIds.Sort(); + } + + public override void OnInspectorGUI() + { + var test = target as LotLoadingTest; + + Core.InitializeCore(); + + string[] noptions = NhoodNames.ToArray(); + int nindex = EditorGUILayout.Popup("Neighborhood", NhoodNames.IndexOf(test.NeighborhoodPrefix), noptions); + if (nindex > -1) + { + test.NeighborhoodPrefix = NhoodNames[nindex]; + } + + if (test.NeighborhoodPrefix != _cachedNhood) + { + PopulateLotList(test.NeighborhoodPrefix); + } + + string[] options = LotIds.Select(x => "Lot " + x.ToString()).ToArray(); + int index = EditorGUILayout.Popup("Lot ID", LotIds.IndexOf(test.LotID), options); + if (index > -1) + { + test.LotID = LotIds[index]; + } + + WallsMode walls = (WallsMode)EditorGUILayout.EnumPopup("Walls", test.Mode); + test.Mode = walls; + + int floor = EditorGUILayout.IntSlider(test.Floor, 1, test.MaxFloor + test.BaseFloor); + test.Floor = floor; + + test.Changed(); + } + } +} diff --git a/Assets/Scripts/OpenTS2/Engine/JSONPathProvider.cs.meta b/Assets/Editor/OpenTS2/Engine/Tests/LotLoadingTestEditor.cs.meta similarity index 83% rename from Assets/Scripts/OpenTS2/Engine/JSONPathProvider.cs.meta rename to Assets/Editor/OpenTS2/Engine/Tests/LotLoadingTestEditor.cs.meta index 6008ddae..c71c12bf 100644 --- a/Assets/Scripts/OpenTS2/Engine/JSONPathProvider.cs.meta +++ b/Assets/Editor/OpenTS2/Engine/Tests/LotLoadingTestEditor.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: a83b704d9e062644e8cd36decb09fe79 +guid: fbf4f776b512a4840bf0a9848a51ded5 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/Editor/IDGenerator.cs b/Assets/Editor/OpenTS2/IDGenerator.cs similarity index 98% rename from Assets/Editor/IDGenerator.cs rename to Assets/Editor/OpenTS2/IDGenerator.cs index 6eea622d..f318dcc3 100644 --- a/Assets/Editor/IDGenerator.cs +++ b/Assets/Editor/OpenTS2/IDGenerator.cs @@ -5,7 +5,7 @@ using UnityEditor; using OpenTS2.Common; -namespace OpenTS2.Editor +namespace OpenTS2 { class IDGenerator : EditorWindow { diff --git a/Assets/Editor/IDGenerator.cs.meta b/Assets/Editor/OpenTS2/IDGenerator.cs.meta similarity index 100% rename from Assets/Editor/IDGenerator.cs.meta rename to Assets/Editor/OpenTS2/IDGenerator.cs.meta diff --git a/Assets/Editor/OpenTS2/NeighborManagerEditor.cs b/Assets/Editor/OpenTS2/NeighborManagerEditor.cs new file mode 100644 index 00000000..cc6b4f8d --- /dev/null +++ b/Assets/Editor/OpenTS2/NeighborManagerEditor.cs @@ -0,0 +1,40 @@ +using OpenTS2.Content; +using OpenTS2.Game; +using OpenTS2.SimAntics; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEditor; +using UnityEngine; + +namespace OpenTS2 +{ + [CustomEditor(typeof(NeighborManager))] + public class NeighborManagerEditor : Editor + { + private bool _showNeighbors = false; + public override void OnInspectorGUI() + { + DrawDefaultInspector(); + var neighborManager = target as NeighborManager; + _showNeighbors = EditorGUILayout.Foldout(_showNeighbors, "Neighbors"); + if (_showNeighbors) + { + var neighbors = neighborManager.Neighbors; + EditorGUI.indentLevel++; + foreach(var neighbor in neighbors) + { + GUILayout.BeginVertical("box"); + GUILayout.Label($"{neighbor.ObjectDefinition.FileName}"); + GUILayout.Label($"Neighbor ID {neighbor.Id}"); + GUILayout.Label($"Object GUID 0x{neighbor.GUID:X8}"); + GUILayout.EndVertical(); + } + EditorGUI.indentLevel--; + } + } + } +} diff --git a/Assets/Scripts/OpenTS2/Engine/Main.cs.meta b/Assets/Editor/OpenTS2/NeighborManagerEditor.cs.meta similarity index 83% rename from Assets/Scripts/OpenTS2/Engine/Main.cs.meta rename to Assets/Editor/OpenTS2/NeighborManagerEditor.cs.meta index cd8b5823..ef61bb86 100644 --- a/Assets/Scripts/OpenTS2/Engine/Main.cs.meta +++ b/Assets/Editor/OpenTS2/NeighborManagerEditor.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 02fb01ed757e43f40a06721007d929e6 +guid: 38f85ef134e1f9e418841c947f7c7a21 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/Editor/OpenTS2/SPXConverter.cs b/Assets/Editor/OpenTS2/SPXConverter.cs new file mode 100644 index 00000000..f82a9586 --- /dev/null +++ b/Assets/Editor/OpenTS2/SPXConverter.cs @@ -0,0 +1,139 @@ +using OpenTS2.Common; +using OpenTS2.Content; +using OpenTS2.Content.DBPF; +using OpenTS2.Engine; +using OpenTS2.Files; +using OpenTS2.Files.Formats.DBPF; +using OpenTS2.Files.Formats.SPX; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using UnityEditor; +using UnityEngine; + +namespace OpenTS2 +{ + public class SPXConverter + { + [MenuItem("OpenTS2/Experiments/Convert all SPX to WAV")] + private static void ConvertSPX() + { + var baseGameOnly = false; + var compressed = false; + if (!EditorUtility.DisplayDialog("SPX to WAV", "This operation will convert ALL SPX resources to WAV. This will take a while and use a lot of resources. Proceed?", "Yes", "No")) + return; + baseGameOnly = EditorUtility.DisplayDialog("SPX to WAV", "Which products do you want to convert?", "Base-Game only", "All products"); + compressed = EditorUtility.DisplayDialog("SPX to WAV", "Do you want to compress the resulting packages?", "Yes", "No"); + Core.CoreInitialized = false; + Core.InitializeCore(); + if (baseGameOnly) + EPManager.Instance.InstalledProducts = (int)ProductFlags.BaseGame; + var epManager = EPManager.Instance; + var products = Filesystem.GetProductDirectories(); + var contentManager = ContentManager.Instance; + + foreach (var product in products) + { + var packages = Filesystem.GetPackagesInDirectory(Path.Combine(product, "TSData/Res/Sound")); + contentManager.AddPackages(packages); + } + + var audioResources = contentManager.ResourceMap.Where(x => x.Key.TypeID == TypeIDs.AUDIO); + var speechResources = new List(); + var speechPackages = new HashSet(); + Debug.Log($"Found {audioResources.Count()} Audio Resources."); + Debug.Log($"Looking for speech resources..."); + + new Thread(async () => + { + foreach (var audioResource in audioResources) + { + try + { + var audioData = audioResource.Value.GetBytes(); + var magic = Encoding.UTF8.GetString(audioData, 0, 2); + if (magic == "SP") + { + speechResources.Add(audioResource.Value); + var packageFileName = Path.GetFileName(audioResource.Value.Package.FilePath); + speechPackages.Add(packageFileName); + } + } + catch (Exception) { } + } + + Debug.Log($"Found {speechResources.Count} SPX audio resources, in {speechPackages.Count} packages."); + var packagesStr = "Packages:"; + foreach (var package in speechPackages) + { + packagesStr += $"\n{package}"; + } + Debug.Log(packagesStr); + + GC.Collect(); + foreach (var package in speechPackages) + { + Debug.Log($"Starting work on {package}"); + var newPackage = new DBPFFile(); + newPackage.FilePath = Path.Combine("SPX to WAV", package); + var entriesToDoForThisPackage = new List(); + foreach (var spx in speechResources) + { + try + { + if (spx.Package == null) continue; + if (Path.GetFileName(spx.Package.FilePath) != package) continue; + entriesToDoForThisPackage.Add(spx); + } + catch (Exception e) + { + Debug.LogError(e); + } + } + Debug.Log($"Will convert {entriesToDoForThisPackage.Count} Entries"); + var tasks = new List(); + var centry = 0; + foreach (var entry in entriesToDoForThisPackage) + { + centry += 1; + var capturedEntry = centry; + tasks.Add(Task.Run(() => + { + if (capturedEntry % 500 == 0) + Debug.Log($"Progress: {capturedEntry}/{entriesToDoForThisPackage.Count}"); + try + { + var spxFile = new SPXFile(entry.GetBytes()); + if (spxFile != null && spxFile.DecompressedData != null && spxFile.DecompressedData.Length > 0) + newPackage.Changes.Set(spxFile.DecompressedData, entry.TGI, compressed); + } + catch (Exception e) + { + Debug.LogError(e); + } + })); + } + await Task.WhenAll(tasks).ContinueWith((task) => + { + try + { + Debug.Log("Writing to disk..."); + newPackage.WriteToFile(); + Debug.Log($"Completed {package}!"); + GC.Collect(); + } + catch (Exception e) + { + Debug.LogError(e); + } + }, TaskScheduler.Default); + } + Debug.Log("All SPX has been converted to WAV! Resulting packages have been written to the SPX to WAV folder."); + }).Start(); + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/OpenTS2/Client/Settings.cs.meta b/Assets/Editor/OpenTS2/SPXConverter.cs.meta similarity index 83% rename from Assets/Scripts/OpenTS2/Client/Settings.cs.meta rename to Assets/Editor/OpenTS2/SPXConverter.cs.meta index f9a421c4..4dc48d4d 100644 --- a/Assets/Scripts/OpenTS2/Client/Settings.cs.meta +++ b/Assets/Editor/OpenTS2/SPXConverter.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 08f81d5f7011bb045b66ef335f1f1272 +guid: 03f1324096114f14abd88d030b24354a MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/Editor/OpenTS2/ShaderBuildPreProcessor.cs b/Assets/Editor/OpenTS2/ShaderBuildPreProcessor.cs new file mode 100644 index 00000000..e93bafd2 --- /dev/null +++ b/Assets/Editor/OpenTS2/ShaderBuildPreProcessor.cs @@ -0,0 +1,49 @@ +using System.Collections; +using System.Collections.Generic; +using System.IO; +using UnityEditor; +using UnityEditor.Build; +using UnityEditor.Build.Reporting; +using UnityEditor.Rendering; +using UnityEngine; +using UnityEngine.Rendering; + +namespace OpenTS2 +{ + public class ShaderBuildPreProcessor : IPreprocessBuildWithReport + { + public int callbackOrder => 0; + + public void OnPreprocessBuild(BuildReport report) + { + var allshaders = Directory.GetFiles("Assets/Shaders", "*.shader", SearchOption.AllDirectories); + var graphicsSettings = AssetDatabase.LoadAssetAtPath("ProjectSettings/GraphicsSettings.asset"); + var serializedObject = new SerializedObject(graphicsSettings); + var alwaysIncludedShadersProp = serializedObject.FindProperty("m_AlwaysIncludedShaders"); + + foreach (var shaderPath in allshaders) + { + var shader = AssetDatabase.LoadAssetAtPath(shaderPath); + if (shader == null) + continue; + var alreadyInList = false; + for (var i = 0; i < alwaysIncludedShadersProp.arraySize; i++) + { + var elem = alwaysIncludedShadersProp.GetArrayElementAtIndex(i); + if (elem.objectReferenceValue == shader) + { + alreadyInList = true; + break; + } + } + if (alreadyInList) + continue; + alwaysIncludedShadersProp.InsertArrayElementAtIndex(0); + var arrayElem = alwaysIncludedShadersProp.GetArrayElementAtIndex(0); + arrayElem.objectReferenceValue = shader; + } + + serializedObject.ApplyModifiedProperties(); + } + } +} \ No newline at end of file diff --git a/Assets/Tests/TestMain.cs.meta b/Assets/Editor/OpenTS2/ShaderBuildPreProcessor.cs.meta similarity index 83% rename from Assets/Tests/TestMain.cs.meta rename to Assets/Editor/OpenTS2/ShaderBuildPreProcessor.cs.meta index a922dae2..f7aa1e20 100644 --- a/Assets/Tests/TestMain.cs.meta +++ b/Assets/Editor/OpenTS2/ShaderBuildPreProcessor.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: f85fdb2b65bb11148b76bb8dfc971d6b +guid: f4caf04b0595c5c4f8e91b22f501b249 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/Editor/OpenTS2/SimulatorEditor.cs b/Assets/Editor/OpenTS2/SimulatorEditor.cs new file mode 100644 index 00000000..80d0306d --- /dev/null +++ b/Assets/Editor/OpenTS2/SimulatorEditor.cs @@ -0,0 +1,71 @@ +using OpenTS2.Game; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEditor; +using UnityEngine; + +namespace OpenTS2 +{ + [CustomEditor(typeof(Simulator))] + public class SimulatorEditor : Editor + { + private bool _showGlobals = false; + private bool _showEntities = false; + public override void OnInspectorGUI() + { + DrawDefaultInspector(); + var simulator = target as Simulator; + var vm = simulator.VirtualMachine; + if (vm == null) return; + var entities = vm.Entities; + if (entities == null) return; + + _showGlobals = EditorGUILayout.Foldout(_showGlobals, "Globals"); + if (_showGlobals) + { + EditorGUI.indentLevel++; + for (var i = 0; i < vm.GlobalState.Length; i++) + { + GUILayout.BeginVertical("box"); + var globalName = ((SimAntics.VMGlobals)i).ToString(); + var editedGlobal = EditorGUILayout.TextField(globalName, vm.GlobalState[i].ToString(CultureInfo.InvariantCulture)); + if (short.TryParse(editedGlobal,NumberStyles.Integer, CultureInfo.InvariantCulture, out var res)) + { + if (res != vm.GlobalState[i]) + vm.SetGlobal((ushort)i, res); + } + GUILayout.EndVertical(); + } + EditorGUI.indentLevel--; + } + + _showEntities = EditorGUILayout.Foldout(_showEntities, "Entities"); + if (_showEntities) + { + EditorGUI.indentLevel++; + foreach (var entity in entities) + { + GUILayout.BeginVertical("box"); + GUILayout.Label($"{entity.ID} - {entity.ObjectDefinition.FileName}"); + EditorGUILayout.Separator(); + GUILayout.BeginHorizontal(); + if (GUILayout.Button("Kill")) + { + entity.Delete(); + } + if (GUILayout.Button("Inspect")) + { + VMEntityWindow.Show(entity); + } + GUILayout.EndHorizontal(); + GUILayout.EndVertical(); + } + EditorGUI.indentLevel--; + } + } + } +} diff --git a/Assets/Editor/OpenTS2/SimulatorEditor.cs.meta b/Assets/Editor/OpenTS2/SimulatorEditor.cs.meta new file mode 100644 index 00000000..12edbf77 --- /dev/null +++ b/Assets/Editor/OpenTS2/SimulatorEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 21a864a17b7497444a19c57f9ca0677b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Editor/OpenTS2/VMEntityWindow.cs b/Assets/Editor/OpenTS2/VMEntityWindow.cs new file mode 100644 index 00000000..bb034907 --- /dev/null +++ b/Assets/Editor/OpenTS2/VMEntityWindow.cs @@ -0,0 +1,136 @@ +using OpenTS2.Common; +using OpenTS2.Content; +using OpenTS2.Content.DBPF; +using OpenTS2.Files.Formats.DBPF; +using OpenTS2.SimAntics; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEditor; +using UnityEngine; + +namespace OpenTS2 +{ + public class VMEntityWindow : EditorWindow + { + public VMEntity Entity; + private ContentManager _contentManager; + private List _attributeNames; + private List _semiAttributeNames; + private Vector2 _scrollbarPosition = Vector2.zero; + private bool _showTemps = false; + private bool _showAttributes = false; + private bool _showSemiAttributes = false; + private bool _showObjectData = false; + public static void Show(VMEntity entity) + { + var window = CreateWindow(typeof(VMEntityWindow)); + window.Initialize(entity); + } + + public void Initialize(VMEntity entity) + { + _attributeNames = new List(); + _semiAttributeNames = new List(); + _contentManager = ContentManager.Instance; + Entity = entity; + titleContent = new GUIContent($"VM Entity: {Entity.ObjectDefinition.FileName} ({Entity.ID})"); + + var attrStringSet = _contentManager.GetAsset(new ResourceKey(0x100, Entity.PrivateGroupID, TypeIDs.STR)); + var semiAttrStringSet = _contentManager.GetAsset(new ResourceKey(0x100, Entity.SemiGlobalGroupID, TypeIDs.STR)); + + if (attrStringSet != null) + { + foreach (var strValue in attrStringSet.StringData.Strings[Languages.USEnglish]) + _attributeNames.Add(strValue.Value); + } + + if (semiAttrStringSet != null) + { + foreach (var strValue in semiAttrStringSet.StringData.Strings[Languages.USEnglish]) + _semiAttributeNames.Add(strValue.Value); + } + } + + private void DisplayEditableField(string name, ref short value) + { + var editedValue = EditorGUILayout.TextField(name, value.ToString(CultureInfo.InvariantCulture)); + if (short.TryParse(editedValue, NumberStyles.Integer, CultureInfo.InvariantCulture, out short res)) + { + if (res != value) + value = res; + } + } + + private void OnGUI() + { + _scrollbarPosition = EditorGUILayout.BeginScrollView(_scrollbarPosition); + + _showObjectData = EditorGUILayout.Foldout(_showObjectData, "Object Data"); + if (_showObjectData) + { + EditorGUI.indentLevel++; + for (var i = 0; i < Entity.ObjectData.Length; i++) + { + GUILayout.BeginVertical("box"); + DisplayEditableField(((VMObjectData)i).ToString(), ref Entity.ObjectData[i]); + GUILayout.EndVertical(); + } + EditorGUI.indentLevel--; + } + + _showAttributes = EditorGUILayout.Foldout(_showAttributes, "Attributes"); + if (_showAttributes) + { + EditorGUI.indentLevel++; + for (var i = 0; i < Entity.Attributes.Length; i++) + { + var attributeName = $"Attribute {i}"; + if (_attributeNames.Count > i && !string.IsNullOrEmpty(_attributeNames[i])) + { + attributeName = _attributeNames[i]; + } + GUILayout.BeginVertical("box"); + DisplayEditableField(attributeName, ref Entity.Attributes[i]); + GUILayout.EndVertical(); + } + EditorGUI.indentLevel--; + } + + _showSemiAttributes = EditorGUILayout.Foldout(_showSemiAttributes, "Semi-Attributes"); + if (_showSemiAttributes) + { + EditorGUI.indentLevel++; + for (var i = 0; i < Entity.SemiAttributes.Length; i++) + { + var attributeName = $"Attribute {i}"; + if (_semiAttributeNames.Count > i && !string.IsNullOrEmpty(_semiAttributeNames[i])) + { + attributeName = _semiAttributeNames[i]; + } + GUILayout.BeginVertical("box"); + DisplayEditableField(attributeName, ref Entity.SemiAttributes[i]); + GUILayout.EndVertical(); + } + EditorGUI.indentLevel--; + } + + _showTemps = EditorGUILayout.Foldout(_showTemps, "Temps"); + if (_showTemps) + { + EditorGUI.indentLevel++; + for (var i = 0; i < Entity.Temps.Length; i++) + { + GUILayout.BeginVertical("box"); + DisplayEditableField($"Temp {i}", ref Entity.Temps[i]); + GUILayout.EndVertical(); + } + EditorGUI.indentLevel--; + } + EditorGUILayout.EndScrollView(); + } + } +} diff --git a/Assets/Editor/OpenTS2/VMEntityWindow.cs.meta b/Assets/Editor/OpenTS2/VMEntityWindow.cs.meta new file mode 100644 index 00000000..136f0c5a --- /dev/null +++ b/Assets/Editor/OpenTS2/VMEntityWindow.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0e76ea6bacd99f64980a82d87ea47c63 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Materials/Build.meta b/Assets/Materials/Build.meta new file mode 100644 index 00000000..d0de8cad --- /dev/null +++ b/Assets/Materials/Build.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b8bc301eacaa25d4a9bbdf35f989ad2e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Materials/Build/WandAreaBrush.mat b/Assets/Materials/Build/WandAreaBrush.mat new file mode 100644 index 00000000..c7c6e3bb --- /dev/null +++ b/Assets/Materials/Build/WandAreaBrush.mat @@ -0,0 +1,79 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 6 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: WandAreaBrush + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: _ALPHAPREMULTIPLY_ON + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: 3000 + stringTagMap: + RenderType: Transparent + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 10 + - _GlossMapScale: 1 + - _Glossiness: 0.5 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 3 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 0 + m_Colors: + - _Color: {r: 0.031886935, g: 1, b: 0, a: 0.48235294} + - _EmissionColor: {r: 0.014443844, g: 0.014443844, b: 0.014443844, a: 1} + m_BuildTextureStacks: [] diff --git a/Assets/Materials/Build/WandAreaBrush.mat.meta b/Assets/Materials/Build/WandAreaBrush.mat.meta new file mode 100644 index 00000000..fce4f1f5 --- /dev/null +++ b/Assets/Materials/Build/WandAreaBrush.mat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9e00eb9bc0cd7be478e657c251ce0680 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Materials/Build/WandTop.mat b/Assets/Materials/Build/WandTop.mat new file mode 100644 index 00000000..03962f30 --- /dev/null +++ b/Assets/Materials/Build/WandTop.mat @@ -0,0 +1,82 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 6 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: WandTop + m_Shader: {fileID: 4800000, guid: 9027c75630615624b8d7e4b02852aa4e, type: 3} + m_ShaderKeywords: + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _Dst: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 0.5 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _ScaleX: 1 + - _ScaleY: 1 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _Src: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 1, g: 1, b: 1, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + m_BuildTextureStacks: [] diff --git a/Assets/Materials/Build/WandTop.mat.meta b/Assets/Materials/Build/WandTop.mat.meta new file mode 100644 index 00000000..05bed763 --- /dev/null +++ b/Assets/Materials/Build/WandTop.mat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5d46dd5277a083f49992dd646af64e34 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/NAudio.meta b/Assets/Plugins/NAudio.meta new file mode 100644 index 00000000..9f06f59a --- /dev/null +++ b/Assets/Plugins/NAudio.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 96ddfba2910122b40ae2f14e29c000f2 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/NAudio/NAudio.dll b/Assets/Plugins/NAudio/NAudio.dll new file mode 100644 index 00000000..553425e1 Binary files /dev/null and b/Assets/Plugins/NAudio/NAudio.dll differ diff --git a/Assets/Plugins/NAudio/NAudio.dll.meta b/Assets/Plugins/NAudio/NAudio.dll.meta new file mode 100644 index 00000000..87f44377 --- /dev/null +++ b/Assets/Plugins/NAudio/NAudio.dll.meta @@ -0,0 +1,33 @@ +fileFormatVersion: 2 +guid: 16ab0fc7a19378e4ba4779314304ac31 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Any: + second: + enabled: 1 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + Windows Store Apps: WindowsStoreApps + second: + enabled: 0 + settings: + CPU: AnyCPU + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/NAudio/NAudio.xml b/Assets/Plugins/NAudio/NAudio.xml new file mode 100644 index 00000000..39108b5b --- /dev/null +++ b/Assets/Plugins/NAudio/NAudio.xml @@ -0,0 +1,22556 @@ + + + + NAudio + + + + + a-law decoder + based on code from: + http://hazelware.luggle.com/tutorials/mulawcompression.html + + + + + only 512 bytes required, so just use a lookup + + + + + Converts an a-law encoded byte to a 16 bit linear sample + + a-law encoded byte + Linear sample + + + + A-law encoder + + + + + Encodes a single 16 bit sample to a-law + + 16 bit PCM sample + a-law encoded byte + + + + SpanDSP - a series of DSP components for telephony + + g722_decode.c - The ITU G.722 codec, decode part. + + Written by Steve Underwood <steveu@coppice.org> + + Copyright (C) 2005 Steve Underwood + Ported to C# by Mark Heath 2011 + + Despite my general liking of the GPL, I place my own contributions + to this code in the public domain for the benefit of all mankind - + even the slimy ones who might try to proprietize my work and use it + to my detriment. + + Based in part on a single channel G.722 codec which is: + Copyright (c) CMU 1993 + Computer Science, Speech Group + Chengxiang Lu and Alex Hauptmann + + + + + hard limits to 16 bit samples + + + + + Decodes a buffer of G722 + + Codec state + Output buffer (to contain decompressed PCM samples) + + Number of bytes in input G722 data to decode + Number of samples written into output buffer + + + + Encodes a buffer of G722 + + Codec state + Output buffer (to contain encoded G722) + PCM 16 bit samples to encode + Number of samples in the input buffer to encode + Number of encoded bytes written into output buffer + + + + Stores state to be used between calls to Encode or Decode + + + + + ITU Test Mode + TRUE if the operating in the special ITU test mode, with the band split filters disabled. + + + + + TRUE if the G.722 data is packed + + + + + 8kHz Sampling + TRUE if encode from 8k samples/second + + + + + Bits Per Sample + 6 for 48000kbps, 7 for 56000kbps, or 8 for 64000kbps. + + + + + Signal history for the QMF (x) + + + + + Band + + + + + In bit buffer + + + + + Number of bits in InBuffer + + + + + Out bit buffer + + + + + Number of bits in OutBuffer + + + + + Creates a new instance of G722 Codec State for a + new encode or decode session + + Bitrate (typically 64000) + Special options + + + + Band data for G722 Codec + + + + s + + + sp + + + sz + + + r + + + a + + + ap + + + p + + + d + + + b + + + bp + + + sg + + + nb + + + det + + + + G722 Flags + + + + + None + + + + + Using a G722 sample rate of 8000 + + + + + Packed + + + + + mu-law decoder + based on code from: + http://hazelware.luggle.com/tutorials/mulawcompression.html + + + + + only 512 bytes required, so just use a lookup + + + + + Converts a mu-law encoded byte to a 16 bit linear sample + + mu-law encoded byte + Linear sample + + + + mu-law encoder + based on code from: + http://hazelware.luggle.com/tutorials/mulawcompression.html + + + + + Encodes a single 16 bit sample to mu-law + + 16 bit PCM sample + mu-law encoded byte + + + + Audio Capture Client + + + + + Gets a pointer to the buffer + + Pointer to the buffer + + + + Gets a pointer to the buffer + + Number of frames to read + Buffer flags + Pointer to the buffer + + + + Gets the size of the next packet + + + + + Release buffer + + Number of frames written + + + + Release the COM object + + + + + Windows CoreAudio AudioClient + + + + + Retrieves the stream format that the audio engine uses for its internal processing of shared-mode streams. + Can be called before initialize + + + + + Initializes the Audio Client + + Share Mode + Stream Flags + Buffer Duration + Periodicity + Wave Format + Audio Session GUID (can be null) + + + + Retrieves the size (maximum capacity) of the audio buffer associated with the endpoint. (must initialize first) + + + + + Retrieves the maximum latency for the current stream and can be called any time after the stream has been initialized. + + + + + Retrieves the number of frames of padding in the endpoint buffer (must initialize first) + + + + + Retrieves the length of the periodic interval separating successive processing passes by the audio engine on the data in the endpoint buffer. + (can be called before initialize) + + + + + Gets the minimum device period + (can be called before initialize) + + + + + Returns the AudioStreamVolume service for this AudioClient. + + + This returns the AudioStreamVolume object ONLY for shared audio streams. + + + This is thrown when an exclusive audio stream is being used. + + + + + Gets the AudioClockClient service + + + + + Gets the AudioRenderClient service + + + + + Gets the AudioCaptureClient service + + + + + Determines whether if the specified output format is supported + + The share mode. + The desired format. + True if the format is supported + + + + Determines if the specified output format is supported in shared mode + + Share Mode + Desired Format + Output The closest match format. + True if the format is supported + + + + Starts the audio stream + + + + + Stops the audio stream. + + + + + Set the Event Handle for buffer synchro. + + The Wait Handle to setup + + + + Resets the audio stream + Reset is a control method that the client calls to reset a stopped audio stream. + Resetting the stream flushes all pending data and resets the audio clock stream + position to 0. This method fails if it is called on a stream that is not stopped + + + + + Dispose + + + + + Audio Client Buffer Flags + + + + + None + + + + + AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY + + + + + AUDCLNT_BUFFERFLAGS_SILENT + + + + + AUDCLNT_BUFFERFLAGS_TIMESTAMP_ERROR + + + + + The AudioClientProperties structure is used to set the parameters that describe the properties of the client's audio stream. + + http://msdn.microsoft.com/en-us/library/windows/desktop/hh968105(v=vs.85).aspx + + + + The size of the buffer for the audio stream. + + + + + Boolean value to indicate whether or not the audio stream is hardware-offloaded + + + + + An enumeration that is used to specify the category of the audio stream. + + + + + A bit-field describing the characteristics of the stream. Supported in Windows 8.1 and later. + + + + + AUDCLNT_SHAREMODE + + + + + AUDCLNT_SHAREMODE_SHARED, + + + + + AUDCLNT_SHAREMODE_EXCLUSIVE + + + + + AUDCLNT_STREAMFLAGS + + + + + None + + + + + AUDCLNT_STREAMFLAGS_CROSSPROCESS + + + + + AUDCLNT_STREAMFLAGS_LOOPBACK + + + + + AUDCLNT_STREAMFLAGS_EVENTCALLBACK + + + + + AUDCLNT_STREAMFLAGS_NOPERSIST + + + + + Defines values that describe the characteristics of an audio stream. + + + + + No stream options. + + + + + The audio stream is a 'raw' stream that bypasses all signal processing except for endpoint specific, always-on processing in the APO, driver, and hardware. + + + + + Audio Clock Client + + + + + Characteristics + + + + + Frequency + + + + + Get Position + + + + + Adjusted Position + + + + + Can Adjust Position + + + + + Dispose + + + + + Audio Endpoint Volume Channel + + + + + GUID to pass to AudioEndpointVolumeCallback + + + + + Volume Level + + + + + Volume Level Scalar + + + + + Audio Endpoint Volume Channels + + + + + Channel Count + + + + + Indexer - get a specific channel + + + + + Audio Endpoint Volume Notifiaction Delegate + + Audio Volume Notification Data + + + + Audio Endpoint Volume Step Information + + + + + Step + + + + + StepCount + + + + + Audio Endpoint Volume Volume Range + + + + + Minimum Decibels + + + + + Maximum Decibels + + + + + Increment Decibels + + + + + Audio Meter Information Channels + + + + + Metering Channel Count + + + + + Get Peak value + + Channel index + Peak value + + + + Audio Render Client + + + + + Gets a pointer to the buffer + + Number of frames requested + Pointer to the buffer + + + + Release buffer + + Number of frames written + Buffer flags + + + + Release the COM object + + + + + AudioSessionControl object for information + regarding an audio session + + + + + Constructor. + + + + + + Dispose + + + + + Finalizer + + + + + Audio meter information of the audio session. + + + + + Simple audio volume of the audio session (for volume and mute status). + + + + + The current state of the audio session. + + + + + The name of the audio session. + + + + + the path to the icon shown in the mixer. + + + + + The session identifier of the audio session. + + + + + The session instance identifier of the audio session. + + + + + The process identifier of the audio session. + + + + + Is the session a system sounds session. + + + + + the grouping param for an audio session grouping + + + + + + For chanigng the grouping param and supplying the context of said change + + + + + + + Registers an even client for callbacks + + + + + + Unregisters an event client from receiving callbacks + + + + + + AudioSessionEvents callback implementation + + + + + Constructor. + + + + + + Notifies the client that the display name for the session has changed. + + The new display name for the session. + A user context value that is passed to the notification callback. + An HRESULT code indicating whether the operation succeeded of failed. + + + + Notifies the client that the display icon for the session has changed. + + The path for the new display icon for the session. + A user context value that is passed to the notification callback. + An HRESULT code indicating whether the operation succeeded of failed. + + + + Notifies the client that the volume level or muting state of the session has changed. + + The new volume level for the audio session. + The new muting state. + A user context value that is passed to the notification callback. + An HRESULT code indicating whether the operation succeeded of failed. + + + + Notifies the client that the volume level of an audio channel in the session submix has changed. + + The channel count. + An array of volumnes cooresponding with each channel index. + The number of the channel whose volume level changed. + A user context value that is passed to the notification callback. + An HRESULT code indicating whether the operation succeeded of failed. + + + + Notifies the client that the grouping parameter for the session has changed. + + The new grouping parameter for the session. + A user context value that is passed to the notification callback. + An HRESULT code indicating whether the operation succeeded of failed. + + + + Notifies the client that the stream-activity state of the session has changed. + + The new session state. + An HRESULT code indicating whether the operation succeeded of failed. + + + + Notifies the client that the session has been disconnected. + + The reason that the audio session was disconnected. + An HRESULT code indicating whether the operation succeeded of failed. + + + + AudioSessionManager + + Designed to manage audio sessions and in particuar the + SimpleAudioVolume interface to adjust a session volume + + + + + + + + + + + + Occurs when audio session has been added (for example run another program that use audio playback). + + + + + SimpleAudioVolume object + for adjusting the volume for the user session + + + + + AudioSessionControl object + for registring for callbacks and other session information + + + + + Refresh session of current device. + + + + + Returns list of sessions of current device. + + + + + Dispose. + + + + + Finalizer. + + + + + Specifies the category of an audio stream. + + + + + Other audio stream. + + + + + Media that will only stream when the app is in the foreground. + + + + + Media that can be streamed when the app is in the background. + + + + + Real-time communications, such as VOIP or chat. + + + + + Alert sounds. + + + + + Sound effects. + + + + + Game sound effects. + + + + + Background audio for games. + + + + + Manages the AudioStreamVolume for the . + + + + + Verify that the channel index is valid. + + + + + + + Return the current stream volumes for all channels + + An array of volume levels between 0.0 and 1.0 for each channel in the audio stream. + + + + Returns the current number of channels in this audio stream. + + + + + Return the current volume for the requested channel. + + The 0 based index into the channels. + The volume level for the channel between 0.0 and 1.0. + + + + Set the volume level for each channel of the audio stream. + + An array of volume levels (between 0.0 and 1.0) one for each channel. + + A volume level MUST be supplied for reach channel in the audio stream. + + + Thrown when does not contain elements. + + + + + Sets the volume level for one channel in the audio stream. + + The 0-based index into the channels to adjust the volume of. + The volume level between 0.0 and 1.0 for this channel of the audio stream. + + + + Dispose + + + + + Release/cleanup objects during Dispose/finalization. + + True if disposing and false if being finalized. + + + + Audio Volume Notification Data + + + + + Event Context + + + + + Muted + + + + + Guid that raised the event + + + + + Master Volume + + + + + Channels + + + + + Channel Volume + + + + + Audio Volume Notification Data + + + + + + + + + + Audio Client WASAPI Error Codes (HResult) + + + + + AUDCLNT_E_NOT_INITIALIZED + + + + + AUDCLNT_E_UNSUPPORTED_FORMAT + + + + + AUDCLNT_E_DEVICE_IN_USE + + + + + AUDCLNT_E_RESOURCES_INVALIDATED + + + + + Defined in AudioClient.h + + + + + Defined in AudioClient.h + + + + + Windows CoreAudio IAudioSessionControl interface + Defined in AudioPolicy.h + + + + + Retrieves the current state of the audio session. + + Receives the current session state. + An HRESULT code indicating whether the operation succeeded of failed. + + + + Retrieves the display name for the audio session. + + Receives a string that contains the display name. + An HRESULT code indicating whether the operation succeeded of failed. + + + + Assigns a display name to the current audio session. + + A string that contains the new display name for the session. + A user context value that is passed to the notification callback. + An HRESULT code indicating whether the operation succeeded of failed. + + + + Retrieves the path for the display icon for the audio session. + + Receives a string that specifies the fully qualified path of the file that contains the icon. + An HRESULT code indicating whether the operation succeeded of failed. + + + + Assigns a display icon to the current session. + + A string that specifies the fully qualified path of the file that contains the new icon. + A user context value that is passed to the notification callback. + An HRESULT code indicating whether the operation succeeded of failed. + + + + Retrieves the grouping parameter of the audio session. + + Receives the grouping parameter ID. + An HRESULT code indicating whether the operation succeeded of failed. + + + + Assigns a session to a grouping of sessions. + + The new grouping parameter ID. + A user context value that is passed to the notification callback. + An HRESULT code indicating whether the operation succeeded of failed. + + + + Registers the client to receive notifications of session events, including changes in the session state. + + A client-implemented interface. + An HRESULT code indicating whether the operation succeeded of failed. + + + + Deletes a previous registration by the client to receive notifications. + + A client-implemented interface. + An HRESULT code indicating whether the operation succeeded of failed. + + + + Windows CoreAudio IAudioSessionControl interface + Defined in AudioPolicy.h + + + + + Retrieves the current state of the audio session. + + Receives the current session state. + An HRESULT code indicating whether the operation succeeded of failed. + + + + Retrieves the display name for the audio session. + + Receives a string that contains the display name. + An HRESULT code indicating whether the operation succeeded of failed. + + + + Assigns a display name to the current audio session. + + A string that contains the new display name for the session. + A user context value that is passed to the notification callback. + An HRESULT code indicating whether the operation succeeded of failed. + + + + Retrieves the path for the display icon for the audio session. + + Receives a string that specifies the fully qualified path of the file that contains the icon. + An HRESULT code indicating whether the operation succeeded of failed. + + + + Assigns a display icon to the current session. + + A string that specifies the fully qualified path of the file that contains the new icon. + A user context value that is passed to the notification callback. + An HRESULT code indicating whether the operation succeeded of failed. + + + + Retrieves the grouping parameter of the audio session. + + Receives the grouping parameter ID. + An HRESULT code indicating whether the operation succeeded of failed. + + + + Assigns a session to a grouping of sessions. + + The new grouping parameter ID. + A user context value that is passed to the notification callback. + An HRESULT code indicating whether the operation succeeded of failed. + + + + Registers the client to receive notifications of session events, including changes in the session state. + + A client-implemented interface. + An HRESULT code indicating whether the operation succeeded of failed. + + + + Deletes a previous registration by the client to receive notifications. + + A client-implemented interface. + An HRESULT code indicating whether the operation succeeded of failed. + + + + Retrieves the identifier for the audio session. + + Receives the session identifier. + An HRESULT code indicating whether the operation succeeded of failed. + + + + Retrieves the identifier of the audio session instance. + + Receives the identifier of a particular instance. + An HRESULT code indicating whether the operation succeeded of failed. + + + + Retrieves the process identifier of the audio session. + + Receives the process identifier of the audio session. + An HRESULT code indicating whether the operation succeeded of failed. + + + + Indicates whether the session is a system sounds session. + + An HRESULT code indicating whether the operation succeeded of failed. + + + + Enables or disables the default stream attenuation experience (auto-ducking) provided by the system. + + A variable that enables or disables system auto-ducking. + An HRESULT code indicating whether the operation succeeded of failed. + + + + Defines constants that indicate the current state of an audio session. + + + MSDN Reference: http://msdn.microsoft.com/en-us/library/dd370792.aspx + + + + + The audio session is inactive. + + + + + The audio session is active. + + + + + The audio session has expired. + + + + + Defines constants that indicate a reason for an audio session being disconnected. + + + MSDN Reference: Unknown + + + + + The user removed the audio endpoint device. + + + + + The Windows audio service has stopped. + + + + + The stream format changed for the device that the audio session is connected to. + + + + + The user logged off the WTS session that the audio session was running in. + + + + + The WTS session that the audio session was running in was disconnected. + + + + + The (shared-mode) audio session was disconnected to make the audio endpoint device available for an exclusive-mode connection. + + + + + Windows CoreAudio IAudioSessionControl interface + Defined in AudioPolicy.h + + + + + Notifies the client that the display name for the session has changed. + + The new display name for the session. + A user context value that is passed to the notification callback. + An HRESULT code indicating whether the operation succeeded of failed. + + + + Notifies the client that the display icon for the session has changed. + + The path for the new display icon for the session. + A user context value that is passed to the notification callback. + An HRESULT code indicating whether the operation succeeded of failed. + + + + Notifies the client that the volume level or muting state of the session has changed. + + The new volume level for the audio session. + The new muting state. + A user context value that is passed to the notification callback. + An HRESULT code indicating whether the operation succeeded of failed. + + + + Notifies the client that the volume level of an audio channel in the session submix has changed. + + The channel count. + An array of volumnes cooresponding with each channel index. + The number of the channel whose volume level changed. + A user context value that is passed to the notification callback. + An HRESULT code indicating whether the operation succeeded of failed. + + + + Notifies the client that the grouping parameter for the session has changed. + + The new grouping parameter for the session. + A user context value that is passed to the notification callback. + An HRESULT code indicating whether the operation succeeded of failed. + + + + Notifies the client that the stream-activity state of the session has changed. + + The new session state. + An HRESULT code indicating whether the operation succeeded of failed. + + + + Notifies the client that the session has been disconnected. + + The reason that the audio session was disconnected. + An HRESULT code indicating whether the operation succeeded of failed. + + + + interface to receive session related events + + + + + notification of volume changes including muting of audio session + + the current volume + the current mute state, true muted, false otherwise + + + + notification of display name changed + + the current display name + + + + notification of icon path changed + + the current icon path + + + + notification of the client that the volume level of an audio channel in the session submix has changed + + The channel count. + An array of volumnes cooresponding with each channel index. + The number of the channel whose volume level changed. + + + + notification of the client that the grouping parameter for the session has changed + + >The new grouping parameter for the session. + + + + notification of the client that the stream-activity state of the session has changed + + The new session state. + + + + notification of the client that the session has been disconnected + + The reason that the audio session was disconnected. + + + + Windows CoreAudio IAudioSessionManager interface + Defined in AudioPolicy.h + + + + + Retrieves an audio session control. + + A new or existing session ID. + Audio session flags. + Receives an interface for the audio session. + An HRESULT code indicating whether the operation succeeded of failed. + + + + Retrieves a simple audio volume control. + + A new or existing session ID. + Audio session flags. + Receives an interface for the audio session. + An HRESULT code indicating whether the operation succeeded of failed. + + + + Retrieves an audio session control. + + A new or existing session ID. + Audio session flags. + Receives an interface for the audio session. + An HRESULT code indicating whether the operation succeeded of failed. + + + + Retrieves a simple audio volume control. + + A new or existing session ID. + Audio session flags. + Receives an interface for the audio session. + An HRESULT code indicating whether the operation succeeded of failed. + + + + Windows CoreAudio IAudioSessionNotification interface + Defined in AudioPolicy.h + + + + + + + session being added + An HRESULT code indicating whether the operation succeeded of failed. + + + + Windows CoreAudio ISimpleAudioVolume interface + Defined in AudioClient.h + + + + + Sets the master volume level for the audio session. + + The new volume level expressed as a normalized value between 0.0 and 1.0. + A user context value that is passed to the notification callback. + An HRESULT code indicating whether the operation succeeded of failed. + + + + Retrieves the client volume level for the audio session. + + Receives the volume level expressed as a normalized value between 0.0 and 1.0. + An HRESULT code indicating whether the operation succeeded of failed. + + + + Sets the muting state for the audio session. + + The new muting state. + A user context value that is passed to the notification callback. + An HRESULT code indicating whether the operation succeeded of failed. + + + + Retrieves the current muting state for the audio session. + + Receives the muting state. + An HRESULT code indicating whether the operation succeeded of failed. + + + + is defined in WTypes.h + + + + + Windows CoreAudio IAudioClient interface + Defined in AudioClient.h + + + + + The GetBufferSize method retrieves the size (maximum capacity) of the endpoint buffer. + + + + + The GetService method accesses additional services from the audio client object. + + The interface ID for the requested service. + Pointer to a pointer variable into which the method writes the address of an instance of the requested interface. + + + + defined in MMDeviceAPI.h + + + + + IMMNotificationClient + + + + + Device State Changed + + + + + Device Added + + + + + Device Removed + + + + + Default Device Changed + + + + + Property Value Changed + + + + + + + is defined in propsys.h + + + + + implements IMMDeviceEnumerator + + + + + MMDevice STGM enumeration + + + + + from Propidl.h. + http://msdn.microsoft.com/en-us/library/aa380072(VS.85).aspx + contains a union so we have to do an explicit layout + + + + + Creates a new PropVariant containing a long value + + + + + Helper method to gets blob data + + + + + Interprets a blob as an array of structs + + + + + Gets the type of data in this PropVariant + + + + + Property value + + + + + allows freeing up memory, might turn this into a Dispose method? + + + + + Clears with a known pointer + + + + + Multimedia Device Collection + + + + + Device count + + + + + Get device by index + + Device index + Device at the specified index + + + + Get Enumerator + + Device enumerator + + + + Property Keys + + + + + PKEY_DeviceInterface_FriendlyName + + + + + PKEY_AudioEndpoint_FormFactor + + + + + PKEY_AudioEndpoint_ControlPanelPageProvider + + + + + PKEY_AudioEndpoint_Association + + + + + PKEY_AudioEndpoint_PhysicalSpeakers + + + + + PKEY_AudioEndpoint_GUID + + + + + PKEY_AudioEndpoint_Disable_SysFx + + + + + PKEY_AudioEndpoint_FullRangeSpeakers + + + + + PKEY_AudioEndpoint_Supports_EventDriven_Mode + + + + + PKEY_AudioEndpoint_JackSubType + + + + + PKEY_AudioEngine_DeviceFormat + + + + + PKEY_AudioEngine_OEMFormat + + + + + PKEY _Devie_FriendlyName + + + + + PKEY _Device_IconPath + + + + + Collection of sessions. + + + + + Returns session at index. + + + + + + + Number of current sessions. + + + + + Windows CoreAudio SimpleAudioVolume + + + + + Creates a new Audio endpoint volume + + ISimpleAudioVolume COM interface + + + + Dispose + + + + + Finalizer + + + + + Allows the user to adjust the volume from + 0.0 to 1.0 + + + + + Mute + + + + + Represents state of a capture device + + + + + Not recording + + + + + Beginning to record + + + + + Recording in progress + + + + + Requesting stop + + + + + Audio Capture using Wasapi + See http://msdn.microsoft.com/en-us/library/dd370800%28VS.85%29.aspx + + + + + Indicates recorded data is available + + + + + Indicates that all recorded data has now been received. + + + + + Initialises a new instance of the WASAPI capture class + + + + + Initialises a new instance of the WASAPI capture class + + Capture device to use + + + + Initializes a new instance of the class. + + The capture device. + true if sync is done with event. false use sleep. + + + + Initializes a new instance of the class. + + The capture device. + true if sync is done with event. false use sleep. + Length of the audio buffer in milliseconds. A lower value means lower latency but increased CPU usage. + + + + Share Mode - set before calling StartRecording + + + + + Current Capturing State + + + + + Capturing wave format + + + + + Gets the default audio capture device + + The default audio capture device + + + + To allow overrides to specify different flags (e.g. loopback) + + + + + Start Capturing + + + + + Stop Capturing (requests a stop, wait for RecordingStopped event to know it has finished) + + + + + Dispose + + + + + Audio Endpoint Volume + + + + + GUID to pass to AudioEndpointVolumeCallback + + + + + On Volume Notification + + + + + Volume Range + + + + + Hardware Support + + + + + Step Information + + + + + Channels + + + + + Master Volume Level + + + + + Master Volume Level Scalar + + + + + Mute + + + + + Volume Step Up + + + + + Volume Step Down + + + + + Creates a new Audio endpoint volume + + IAudioEndpointVolume COM interface + + + + Dispose + + + + + Finalizer + + + + + Audio Meter Information + + + + + Peak Values + + + + + Hardware Support + + + + + Master Peak Value + + + + + Device State + + + + + DEVICE_STATE_ACTIVE + + + + + DEVICE_STATE_DISABLED + + + + + DEVICE_STATE_NOTPRESENT + + + + + DEVICE_STATE_UNPLUGGED + + + + + DEVICE_STATEMASK_ALL + + + + + Endpoint Hardware Support + + + + + Volume + + + + + Mute + + + + + Meter + + + + + The EDataFlow enumeration defines constants that indicate the direction + in which audio data flows between an audio endpoint device and an application + + + + + Audio rendering stream. + Audio data flows from the application to the audio endpoint device, which renders the stream. + + + + + Audio capture stream. Audio data flows from the audio endpoint device that captures the stream, + to the application + + + + + Audio rendering or capture stream. Audio data can flow either from the application to the audio + endpoint device, or from the audio endpoint device to the application. + + + + + PROPERTYKEY is defined in wtypes.h + + + + + Format ID + + + + + Property ID + + + + + + + + + + + The ERole enumeration defines constants that indicate the role + that the system has assigned to an audio endpoint device + + + + + Games, system notification sounds, and voice commands. + + + + + Music, movies, narration, and live music recording + + + + + Voice communications (talking to another person). + + + + + MM Device + + + + + Audio Client + + + + + Audio Meter Information + + + + + Audio Endpoint Volume + + + + + AudioSessionManager instance + + + + + Properties + + + + + Friendly name for the endpoint + + + + + Friendly name of device + + + + + Icon path of device + + + + + Device ID + + + + + Data Flow + + + + + Device State + + + + + To string + + + + + MM Device Enumerator + + + + + Creates a new MM Device Enumerator + + + + + Enumerate Audio Endpoints + + Desired DataFlow + State Mask + Device Collection + + + + Get Default Endpoint + + Data Flow + Role + Device + + + + Check to see if a default audio end point exists without needing an exception. + + Data Flow + Role + True if one exists, and false if one does not exist. + + + + Get device by ID + + Device ID + Device + + + + Registers a call back for Device Events + + Object implementing IMMNotificationClient type casted as IMMNotificationClient interface + + + + + Unregisters a call back for Device Events + + Object implementing IMMNotificationClient type casted as IMMNotificationClient interface + + + + + + + + Called to dispose/finalize contained objects. + + True if disposing, false if called from a finalizer. + + + + Property Store class, only supports reading properties at the moment. + + + + + Property Count + + + + + Gets property by index + + Property index + The property + + + + Contains property guid + + Looks for a specific key + True if found + + + + Indexer by guid + + Property Key + Property or null if not found + + + + Gets property key at sepecified index + + Index + Property key + + + + Gets property value at specified index + + Index + Property value + + + + Creates a new property store + + IPropertyStore COM interface + + + + Property Store Property + + + + + Property Key + + + + + Property Value + + + + + Envelope generator (ADSR) + + + + + Envelope State + + + + + Idle + + + + + Attack + + + + + Decay + + + + + Sustain + + + + + Release + + + + + Creates and Initializes an Envelope Generator + + + + + Attack Rate (seconds * SamplesPerSecond) + + + + + Decay Rate (seconds * SamplesPerSecond) + + + + + Release Rate (seconds * SamplesPerSecond) + + + + + Sustain Level (1 = 100%) + + + + + Sets the attack curve + + + + + Sets the decay release curve + + + + + Read the next volume multiplier from the envelope generator + + A volume multiplier + + + + Trigger the gate + + If true, enter attack phase, if false enter release phase (unless already idle) + + + + Current envelope state + + + + + Reset to idle state + + + + + Get the current output level + + + + + Fully managed resampler, based on Cockos WDL Resampler + + + + + Creates a new Resampler + + + + + sets the mode + if sinc set, it overrides interp or filtercnt + + + + + Sets the filter parameters + used for filtercnt>0 but not sinc + + + + + Set feed mode + + if true, that means the first parameter to ResamplePrepare will specify however much input you have, not how much you want + + + + Reset + + + + + Prepare + note that it is safe to call ResamplePrepare without calling ResampleOut (the next call of ResamplePrepare will function as normal) + nb inbuffer was WDL_ResampleSample **, returning a place to put the in buffer, so we return a buffer and offset + + req_samples is output samples desired if !wantInputDriven, or if wantInputDriven is input samples that we have + + + + returns number of samples desired (put these into *inbuffer) + + + + SMB Pitch Shifter + + + + + Pitch Shift + + + + + Pitch Shift + + + + + Short Time Fourier Transform + + + + + BiQuad filter + + + + + Passes a single sample through the filter + + Input sample + Output sample + + + + Set this up as a low pass filter + + Sample Rate + Cut-off Frequency + Bandwidth + + + + Set this up as a peaking EQ + + Sample Rate + Centre Frequency + Bandwidth (Q) + Gain in decibels + + + + Set this as a high pass filter + + + + + Create a low pass filter + + + + + Create a High pass filter + + + + + Create a bandpass filter with constant skirt gain + + + + + Create a bandpass filter with constant peak gain + + + + + Creates a notch filter + + + + + Creaes an all pass filter + + + + + Create a Peaking EQ + + + + + H(s) = A * (s^2 + (sqrt(A)/Q)*s + A)/(A*s^2 + (sqrt(A)/Q)*s + 1) + + + + a "shelf slope" parameter (for shelving EQ only). + When S = 1, the shelf slope is as steep as it can be and remain monotonically + increasing or decreasing gain with frequency. The shelf slope, in dB/octave, + remains proportional to S for all other values for a fixed f0/Fs and dBgain. + Gain in decibels + + + + H(s) = A * (A*s^2 + (sqrt(A)/Q)*s + 1)/(s^2 + (sqrt(A)/Q)*s + A) + + + + + + + + + + Type to represent complex number + + + + + Real Part + + + + + Imaginary Part + + + + + Summary description for FastFourierTransform. + + + + + This computes an in-place complex-to-complex FFT + x and y are the real and imaginary arrays of 2^m points. + + + + + Applies a Hamming Window + + Index into frame + Frame size (e.g. 1024) + Multiplier for Hamming window + + + + Applies a Hann Window + + Index into frame + Frame size (e.g. 1024) + Multiplier for Hann window + + + + Applies a Blackman-Harris Window + + Index into frame + Frame size (e.g. 1024) + Multiplier for Blackmann-Harris window + + + + Summary description for ImpulseResponseConvolution. + + + + + A very simple mono convolution algorithm + + + This will be very slow + + + + + This is actually a downwards normalize for data that will clip + + + + + http://tech.ebu.ch/docs/tech/tech3306-2009.pdf + + + + + WaveFormat + + + + + Data Chunk Position + + + + + Data Chunk Length + + + + + Riff Chunks + + + + + Represents an entry in a Cakewalk drum map + + + + + User customisable note name + + + + + Input MIDI note number + + + + + Output MIDI note number + + + + + Output port + + + + + Output MIDI Channel + + + + + Velocity adjustment + + + + + Velocity scaling - in percent + + + + + Describes this drum map entry + + + + + Represents a Cakewalk Drum Map file (.map) + + + + + Parses a Cakewalk Drum Map file + + Path of the .map file + + + + The drum mappings in this drum map + + + + + Describes this drum map + + + + + MP3 Frame decompressor using the Windows Media MP3 Decoder DMO object + + + + + Initializes a new instance of the DMO MP3 Frame decompressor + + + + + + Converted PCM WaveFormat + + + + + Decompress a single frame of MP3 + + + + + Alerts us that a reposition has occured so the MP3 decoder needs to reset its state + + + + + Dispose of this obejct and clean up resources + + + + + Audio Subtype GUIDs + http://msdn.microsoft.com/en-us/library/windows/desktop/aa372553%28v=vs.85%29.aspx + + + + + Advanced Audio Coding (AAC). + + + + + Not used + + + + + Dolby AC-3 audio over Sony/Philips Digital Interface (S/PDIF). + + + + + Encrypted audio data used with secure audio path. + + + + + Digital Theater Systems (DTS) audio. + + + + + Uncompressed IEEE floating-point audio. + + + + + MPEG Audio Layer-3 (MP3). + + + + + MPEG-1 audio payload. + + + + + Windows Media Audio 9 Voice codec. + + + + + Uncompressed PCM audio. + + + + + Windows Media Audio 9 Professional codec over S/PDIF. + + + + + Windows Media Audio 9 Lossless codec or Windows Media Audio 9.1 codec. + + + + + Windows Media Audio 8 codec, Windows Media Audio 9 codec, or Windows Media Audio 9.1 codec. + + + + + Windows Media Audio 9 Professional codec or Windows Media Audio 9.1 Professional codec. + + + + + Dolby Digital (AC-3). + + + + + MPEG-4 and AAC Audio Types + http://msdn.microsoft.com/en-us/library/windows/desktop/dd317599(v=vs.85).aspx + Reference : wmcodecdsp.h + + + + + Dolby Audio Types + http://msdn.microsoft.com/en-us/library/windows/desktop/dd317599(v=vs.85).aspx + Reference : wmcodecdsp.h + + + + + Dolby Audio Types + http://msdn.microsoft.com/en-us/library/windows/desktop/dd317599(v=vs.85).aspx + Reference : wmcodecdsp.h + + + + + μ-law coding + http://msdn.microsoft.com/en-us/library/windows/desktop/dd390971(v=vs.85).aspx + Reference : Ksmedia.h + + + + + Adaptive delta pulse code modulation (ADPCM) + http://msdn.microsoft.com/en-us/library/windows/desktop/dd390971(v=vs.85).aspx + Reference : Ksmedia.h + + + + + Dolby Digital Plus formatted for HDMI output. + http://msdn.microsoft.com/en-us/library/windows/hardware/ff538392(v=vs.85).aspx + Reference : internet + + + + + MSAudio1 - unknown meaning + Reference : wmcodecdsp.h + + + + + IMA ADPCM ACM Wrapper + + + + + WMSP2 - unknown meaning + Reference: wmsdkidl.h + + + + + Creates an instance of either the sink writer or the source reader. + + + + + Creates an instance of the sink writer or source reader, given a URL. + + + + + Creates an instance of the sink writer or source reader, given an IUnknown pointer. + + + + + CLSID_MFReadWriteClassFactory + + + + + Media Foundation Errors + + + + RANGES + 14000 - 14999 = General Media Foundation errors + 15000 - 15999 = ASF parsing errors + 16000 - 16999 = Media Source errors + 17000 - 17999 = MEDIAFOUNDATION Network Error Events + 18000 - 18999 = MEDIAFOUNDATION WMContainer Error Events + 19000 - 19999 = MEDIAFOUNDATION Media Sink Error Events + 20000 - 20999 = Renderer errors + 21000 - 21999 = Topology Errors + 25000 - 25999 = Timeline Errors + 26000 - 26999 = Unused + 28000 - 28999 = Transform errors + 29000 - 29999 = Content Protection errors + 40000 - 40999 = Clock errors + 41000 - 41999 = MF Quality Management Errors + 42000 - 42999 = MF Transcode API Errors + + + + + MessageId: MF_E_PLATFORM_NOT_INITIALIZED + + MessageText: + + Platform not initialized. Please call MFStartup().%0 + + + + + MessageId: MF_E_BUFFERTOOSMALL + + MessageText: + + The buffer was too small to carry out the requested action.%0 + + + + + MessageId: MF_E_INVALIDREQUEST + + MessageText: + + The request is invalid in the current state.%0 + + + + + MessageId: MF_E_INVALIDSTREAMNUMBER + + MessageText: + + The stream number provided was invalid.%0 + + + + + MessageId: MF_E_INVALIDMEDIATYPE + + MessageText: + + The data specified for the media type is invalid, inconsistent, or not supported by this object.%0 + + + + + MessageId: MF_E_NOTACCEPTING + + MessageText: + + The callee is currently not accepting further input.%0 + + + + + MessageId: MF_E_NOT_INITIALIZED + + MessageText: + + This object needs to be initialized before the requested operation can be carried out.%0 + + + + + MessageId: MF_E_UNSUPPORTED_REPRESENTATION + + MessageText: + + The requested representation is not supported by this object.%0 + + + + + MessageId: MF_E_NO_MORE_TYPES + + MessageText: + + An object ran out of media types to suggest therefore the requested chain of streaming objects cannot be completed.%0 + + + + + MessageId: MF_E_UNSUPPORTED_SERVICE + + MessageText: + + The object does not support the specified service.%0 + + + + + MessageId: MF_E_UNEXPECTED + + MessageText: + + An unexpected error has occurred in the operation requested.%0 + + + + + MessageId: MF_E_INVALIDNAME + + MessageText: + + Invalid name.%0 + + + + + MessageId: MF_E_INVALIDTYPE + + MessageText: + + Invalid type.%0 + + + + + MessageId: MF_E_INVALID_FILE_FORMAT + + MessageText: + + The file does not conform to the relevant file format specification. + + + + + MessageId: MF_E_INVALIDINDEX + + MessageText: + + Invalid index.%0 + + + + + MessageId: MF_E_INVALID_TIMESTAMP + + MessageText: + + An invalid timestamp was given.%0 + + + + + MessageId: MF_E_UNSUPPORTED_SCHEME + + MessageText: + + The scheme of the given URL is unsupported.%0 + + + + + MessageId: MF_E_UNSUPPORTED_BYTESTREAM_TYPE + + MessageText: + + The byte stream type of the given URL is unsupported.%0 + + + + + MessageId: MF_E_UNSUPPORTED_TIME_FORMAT + + MessageText: + + The given time format is unsupported.%0 + + + + + MessageId: MF_E_NO_SAMPLE_TIMESTAMP + + MessageText: + + The Media Sample does not have a timestamp.%0 + + + + + MessageId: MF_E_NO_SAMPLE_DURATION + + MessageText: + + The Media Sample does not have a duration.%0 + + + + + MessageId: MF_E_INVALID_STREAM_DATA + + MessageText: + + The request failed because the data in the stream is corrupt.%0\n. + + + + + MessageId: MF_E_RT_UNAVAILABLE + + MessageText: + + Real time services are not available.%0 + + + + + MessageId: MF_E_UNSUPPORTED_RATE + + MessageText: + + The specified rate is not supported.%0 + + + + + MessageId: MF_E_THINNING_UNSUPPORTED + + MessageText: + + This component does not support stream-thinning.%0 + + + + + MessageId: MF_E_REVERSE_UNSUPPORTED + + MessageText: + + The call failed because no reverse playback rates are available.%0 + + + + + MessageId: MF_E_UNSUPPORTED_RATE_TRANSITION + + MessageText: + + The requested rate transition cannot occur in the current state.%0 + + + + + MessageId: MF_E_RATE_CHANGE_PREEMPTED + + MessageText: + + The requested rate change has been pre-empted and will not occur.%0 + + + + + MessageId: MF_E_NOT_FOUND + + MessageText: + + The specified object or value does not exist.%0 + + + + + MessageId: MF_E_NOT_AVAILABLE + + MessageText: + + The requested value is not available.%0 + + + + + MessageId: MF_E_NO_CLOCK + + MessageText: + + The specified operation requires a clock and no clock is available.%0 + + + + + MessageId: MF_S_MULTIPLE_BEGIN + + MessageText: + + This callback and state had already been passed in to this event generator earlier.%0 + + + + + MessageId: MF_E_MULTIPLE_BEGIN + + MessageText: + + This callback has already been passed in to this event generator.%0 + + + + + MessageId: MF_E_MULTIPLE_SUBSCRIBERS + + MessageText: + + Some component is already listening to events on this event generator.%0 + + + + + MessageId: MF_E_TIMER_ORPHANED + + MessageText: + + This timer was orphaned before its callback time arrived.%0 + + + + + MessageId: MF_E_STATE_TRANSITION_PENDING + + MessageText: + + A state transition is already pending.%0 + + + + + MessageId: MF_E_UNSUPPORTED_STATE_TRANSITION + + MessageText: + + The requested state transition is unsupported.%0 + + + + + MessageId: MF_E_UNRECOVERABLE_ERROR_OCCURRED + + MessageText: + + An unrecoverable error has occurred.%0 + + + + + MessageId: MF_E_SAMPLE_HAS_TOO_MANY_BUFFERS + + MessageText: + + The provided sample has too many buffers.%0 + + + + + MessageId: MF_E_SAMPLE_NOT_WRITABLE + + MessageText: + + The provided sample is not writable.%0 + + + + + MessageId: MF_E_INVALID_KEY + + MessageText: + + The specified key is not valid. + + + + + MessageId: MF_E_BAD_STARTUP_VERSION + + MessageText: + + You are calling MFStartup with the wrong MF_VERSION. Mismatched bits? + + + + + MessageId: MF_E_UNSUPPORTED_CAPTION + + MessageText: + + The caption of the given URL is unsupported.%0 + + + + + MessageId: MF_E_INVALID_POSITION + + MessageText: + + The operation on the current offset is not permitted.%0 + + + + + MessageId: MF_E_ATTRIBUTENOTFOUND + + MessageText: + + The requested attribute was not found.%0 + + + + + MessageId: MF_E_PROPERTY_TYPE_NOT_ALLOWED + + MessageText: + + The specified property type is not allowed in this context.%0 + + + + + MessageId: MF_E_PROPERTY_TYPE_NOT_SUPPORTED + + MessageText: + + The specified property type is not supported.%0 + + + + + MessageId: MF_E_PROPERTY_EMPTY + + MessageText: + + The specified property is empty.%0 + + + + + MessageId: MF_E_PROPERTY_NOT_EMPTY + + MessageText: + + The specified property is not empty.%0 + + + + + MessageId: MF_E_PROPERTY_VECTOR_NOT_ALLOWED + + MessageText: + + The vector property specified is not allowed in this context.%0 + + + + + MessageId: MF_E_PROPERTY_VECTOR_REQUIRED + + MessageText: + + A vector property is required in this context.%0 + + + + + MessageId: MF_E_OPERATION_CANCELLED + + MessageText: + + The operation is cancelled.%0 + + + + + MessageId: MF_E_BYTESTREAM_NOT_SEEKABLE + + MessageText: + + The provided bytestream was expected to be seekable and it is not.%0 + + + + + MessageId: MF_E_DISABLED_IN_SAFEMODE + + MessageText: + + The Media Foundation platform is disabled when the system is running in Safe Mode.%0 + + + + + MessageId: MF_E_CANNOT_PARSE_BYTESTREAM + + MessageText: + + The Media Source could not parse the byte stream.%0 + + + + + MessageId: MF_E_SOURCERESOLVER_MUTUALLY_EXCLUSIVE_FLAGS + + MessageText: + + Mutually exclusive flags have been specified to source resolver. This flag combination is invalid.%0 + + + + + MessageId: MF_E_MEDIAPROC_WRONGSTATE + + MessageText: + + MediaProc is in the wrong state%0 + + + + + MessageId: MF_E_RT_THROUGHPUT_NOT_AVAILABLE + + MessageText: + + Real time I/O service can not provide requested throughput.%0 + + + + + MessageId: MF_E_RT_TOO_MANY_CLASSES + + MessageText: + + The workqueue cannot be registered with more classes.%0 + + + + + MessageId: MF_E_RT_WOULDBLOCK + + MessageText: + + This operation cannot succeed because another thread owns this object.%0 + + + + + MessageId: MF_E_NO_BITPUMP + + MessageText: + + Internal. Bitpump not found.%0 + + + + + MessageId: MF_E_RT_OUTOFMEMORY + + MessageText: + + No more RT memory available.%0 + + + + + MessageId: MF_E_RT_WORKQUEUE_CLASS_NOT_SPECIFIED + + MessageText: + + An MMCSS class has not been set for this work queue.%0 + + + + + MessageId: MF_E_INSUFFICIENT_BUFFER + + MessageText: + + Insufficient memory for response.%0 + + + + + MessageId: MF_E_CANNOT_CREATE_SINK + + MessageText: + + Activate failed to create mediasink. Call OutputNode::GetUINT32(MF_TOPONODE_MAJORTYPE) for more information. %0 + + + + + MessageId: MF_E_BYTESTREAM_UNKNOWN_LENGTH + + MessageText: + + The length of the provided bytestream is unknown.%0 + + + + + MessageId: MF_E_SESSION_PAUSEWHILESTOPPED + + MessageText: + + The media session cannot pause from a stopped state.%0 + + + + + MessageId: MF_S_ACTIVATE_REPLACED + + MessageText: + + The activate could not be created in the remote process for some reason it was replaced with empty one.%0 + + + + + MessageId: MF_E_FORMAT_CHANGE_NOT_SUPPORTED + + MessageText: + + The data specified for the media type is supported, but would require a format change, which is not supported by this object.%0 + + + + + MessageId: MF_E_INVALID_WORKQUEUE + + MessageText: + + The operation failed because an invalid combination of workqueue ID and flags was specified.%0 + + + + + MessageId: MF_E_DRM_UNSUPPORTED + + MessageText: + + No DRM support is available.%0 + + + + + MessageId: MF_E_UNAUTHORIZED + + MessageText: + + This operation is not authorized.%0 + + + + + MessageId: MF_E_OUT_OF_RANGE + + MessageText: + + The value is not in the specified or valid range.%0 + + + + + MessageId: MF_E_INVALID_CODEC_MERIT + + MessageText: + + The registered codec merit is not valid.%0 + + + + + MessageId: MF_E_HW_MFT_FAILED_START_STREAMING + + MessageText: + + Hardware MFT failed to start streaming due to lack of hardware resources.%0 + + + + + MessageId: MF_S_ASF_PARSEINPROGRESS + + MessageText: + + Parsing is still in progress and is not yet complete.%0 + + + + + MessageId: MF_E_ASF_PARSINGINCOMPLETE + + MessageText: + + Not enough data have been parsed to carry out the requested action.%0 + + + + + MessageId: MF_E_ASF_MISSINGDATA + + MessageText: + + There is a gap in the ASF data provided.%0 + + + + + MessageId: MF_E_ASF_INVALIDDATA + + MessageText: + + The data provided are not valid ASF.%0 + + + + + MessageId: MF_E_ASF_OPAQUEPACKET + + MessageText: + + The packet is opaque, so the requested information cannot be returned.%0 + + + + + MessageId: MF_E_ASF_NOINDEX + + MessageText: + + The requested operation failed since there is no appropriate ASF index.%0 + + + + + MessageId: MF_E_ASF_OUTOFRANGE + + MessageText: + + The value supplied is out of range for this operation.%0 + + + + + MessageId: MF_E_ASF_INDEXNOTLOADED + + MessageText: + + The index entry requested needs to be loaded before it can be available.%0 + + + + + MessageId: MF_E_ASF_TOO_MANY_PAYLOADS + + MessageText: + + The packet has reached the maximum number of payloads.%0 + + + + + MessageId: MF_E_ASF_UNSUPPORTED_STREAM_TYPE + + MessageText: + + Stream type is not supported.%0 + + + + + MessageId: MF_E_ASF_DROPPED_PACKET + + MessageText: + + One or more ASF packets were dropped.%0 + + + + + MessageId: MF_E_NO_EVENTS_AVAILABLE + + MessageText: + + There are no events available in the queue.%0 + + + + + MessageId: MF_E_INVALID_STATE_TRANSITION + + MessageText: + + A media source cannot go from the stopped state to the paused state.%0 + + + + + MessageId: MF_E_END_OF_STREAM + + MessageText: + + The media stream cannot process any more samples because there are no more samples in the stream.%0 + + + + + MessageId: MF_E_SHUTDOWN + + MessageText: + + The request is invalid because Shutdown() has been called.%0 + + + + + MessageId: MF_E_MP3_NOTFOUND + + MessageText: + + The MP3 object was not found.%0 + + + + + MessageId: MF_E_MP3_OUTOFDATA + + MessageText: + + The MP3 parser ran out of data before finding the MP3 object.%0 + + + + + MessageId: MF_E_MP3_NOTMP3 + + MessageText: + + The file is not really a MP3 file.%0 + + + + + MessageId: MF_E_MP3_NOTSUPPORTED + + MessageText: + + The MP3 file is not supported.%0 + + + + + MessageId: MF_E_NO_DURATION + + MessageText: + + The Media stream has no duration.%0 + + + + + MessageId: MF_E_INVALID_FORMAT + + MessageText: + + The Media format is recognized but is invalid.%0 + + + + + MessageId: MF_E_PROPERTY_NOT_FOUND + + MessageText: + + The property requested was not found.%0 + + + + + MessageId: MF_E_PROPERTY_READ_ONLY + + MessageText: + + The property is read only.%0 + + + + + MessageId: MF_E_PROPERTY_NOT_ALLOWED + + MessageText: + + The specified property is not allowed in this context.%0 + + + + + MessageId: MF_E_MEDIA_SOURCE_NOT_STARTED + + MessageText: + + The media source is not started.%0 + + + + + MessageId: MF_E_UNSUPPORTED_FORMAT + + MessageText: + + The Media format is recognized but not supported.%0 + + + + + MessageId: MF_E_MP3_BAD_CRC + + MessageText: + + The MPEG frame has bad CRC.%0 + + + + + MessageId: MF_E_NOT_PROTECTED + + MessageText: + + The file is not protected.%0 + + + + + MessageId: MF_E_MEDIA_SOURCE_WRONGSTATE + + MessageText: + + The media source is in the wrong state%0 + + + + + MessageId: MF_E_MEDIA_SOURCE_NO_STREAMS_SELECTED + + MessageText: + + No streams are selected in source presentation descriptor.%0 + + + + + MessageId: MF_E_CANNOT_FIND_KEYFRAME_SAMPLE + + MessageText: + + No key frame sample was found.%0 + + + + + MessageId: MF_E_NETWORK_RESOURCE_FAILURE + + MessageText: + + An attempt to acquire a network resource failed.%0 + + + + + MessageId: MF_E_NET_WRITE + + MessageText: + + Error writing to the network.%0 + + + + + MessageId: MF_E_NET_READ + + MessageText: + + Error reading from the network.%0 + + + + + MessageId: MF_E_NET_REQUIRE_NETWORK + + MessageText: + + Internal. Entry cannot complete operation without network.%0 + + + + + MessageId: MF_E_NET_REQUIRE_ASYNC + + MessageText: + + Internal. Async op is required.%0 + + + + + MessageId: MF_E_NET_BWLEVEL_NOT_SUPPORTED + + MessageText: + + Internal. Bandwidth levels are not supported.%0 + + + + + MessageId: MF_E_NET_STREAMGROUPS_NOT_SUPPORTED + + MessageText: + + Internal. Stream groups are not supported.%0 + + + + + MessageId: MF_E_NET_MANUALSS_NOT_SUPPORTED + + MessageText: + + Manual stream selection is not supported.%0 + + + + + MessageId: MF_E_NET_INVALID_PRESENTATION_DESCRIPTOR + + MessageText: + + Invalid presentation descriptor.%0 + + + + + MessageId: MF_E_NET_CACHESTREAM_NOT_FOUND + + MessageText: + + Cannot find cache stream.%0 + + + + + MessageId: MF_I_MANUAL_PROXY + + MessageText: + + The proxy setting is manual.%0 + + + + duplicate removed + MessageId=17011 Severity=Informational Facility=MEDIAFOUNDATION SymbolicName=MF_E_INVALID_REQUEST + Language=English + The request is invalid in the current state.%0 + . + + MessageId: MF_E_NET_REQUIRE_INPUT + + MessageText: + + Internal. Entry cannot complete operation without input.%0 + + + + + MessageId: MF_E_NET_REDIRECT + + MessageText: + + The client redirected to another server.%0 + + + + + MessageId: MF_E_NET_REDIRECT_TO_PROXY + + MessageText: + + The client is redirected to a proxy server.%0 + + + + + MessageId: MF_E_NET_TOO_MANY_REDIRECTS + + MessageText: + + The client reached maximum redirection limit.%0 + + + + + MessageId: MF_E_NET_TIMEOUT + + MessageText: + + The server, a computer set up to offer multimedia content to other computers, could not handle your request for multimedia content in a timely manner. Please try again later.%0 + + + + + MessageId: MF_E_NET_CLIENT_CLOSE + + MessageText: + + The control socket is closed by the client.%0 + + + + + MessageId: MF_E_NET_BAD_CONTROL_DATA + + MessageText: + + The server received invalid data from the client on the control connection.%0 + + + + + MessageId: MF_E_NET_INCOMPATIBLE_SERVER + + MessageText: + + The server is not a compatible streaming media server.%0 + + + + + MessageId: MF_E_NET_UNSAFE_URL + + MessageText: + + Url.%0 + + + + + MessageId: MF_E_NET_CACHE_NO_DATA + + MessageText: + + Data is not available.%0 + + + + + MessageId: MF_E_NET_EOL + + MessageText: + + End of line.%0 + + + + + MessageId: MF_E_NET_BAD_REQUEST + + MessageText: + + The request could not be understood by the server.%0 + + + + + MessageId: MF_E_NET_INTERNAL_SERVER_ERROR + + MessageText: + + The server encountered an unexpected condition which prevented it from fulfilling the request.%0 + + + + + MessageId: MF_E_NET_SESSION_NOT_FOUND + + MessageText: + + Session not found.%0 + + + + + MessageId: MF_E_NET_NOCONNECTION + + MessageText: + + There is no connection established with the Windows Media server. The operation failed.%0 + + + + + MessageId: MF_E_NET_CONNECTION_FAILURE + + MessageText: + + The network connection has failed.%0 + + + + + MessageId: MF_E_NET_INCOMPATIBLE_PUSHSERVER + + MessageText: + + The Server service that received the HTTP push request is not a compatible version of Windows Media Services (WMS). This error may indicate the push request was received by IIS instead of WMS. Ensure WMS is started and has the HTTP Server control protocol properly enabled and try again.%0 + + + + + MessageId: MF_E_NET_SERVER_ACCESSDENIED + + MessageText: + + The Windows Media server is denying access. The username and/or password might be incorrect.%0 + + + + + MessageId: MF_E_NET_PROXY_ACCESSDENIED + + MessageText: + + The proxy server is denying access. The username and/or password might be incorrect.%0 + + + + + MessageId: MF_E_NET_CANNOTCONNECT + + MessageText: + + Unable to establish a connection to the server.%0 + + + + + MessageId: MF_E_NET_INVALID_PUSH_TEMPLATE + + MessageText: + + The specified push template is invalid.%0 + + + + + MessageId: MF_E_NET_INVALID_PUSH_PUBLISHING_POINT + + MessageText: + + The specified push publishing point is invalid.%0 + + + + + MessageId: MF_E_NET_BUSY + + MessageText: + + The requested resource is in use.%0 + + + + + MessageId: MF_E_NET_RESOURCE_GONE + + MessageText: + + The Publishing Point or file on the Windows Media Server is no longer available.%0 + + + + + MessageId: MF_E_NET_ERROR_FROM_PROXY + + MessageText: + + The proxy experienced an error while attempting to contact the media server.%0 + + + + + MessageId: MF_E_NET_PROXY_TIMEOUT + + MessageText: + + The proxy did not receive a timely response while attempting to contact the media server.%0 + + + + + MessageId: MF_E_NET_SERVER_UNAVAILABLE + + MessageText: + + The server is currently unable to handle the request due to a temporary overloading or maintenance of the server.%0 + + + + + MessageId: MF_E_NET_TOO_MUCH_DATA + + MessageText: + + The encoding process was unable to keep up with the amount of supplied data.%0 + + + + + MessageId: MF_E_NET_SESSION_INVALID + + MessageText: + + Session not found.%0 + + + + + MessageId: MF_E_OFFLINE_MODE + + MessageText: + + The requested URL is not available in offline mode.%0 + + + + + MessageId: MF_E_NET_UDP_BLOCKED + + MessageText: + + A device in the network is blocking UDP traffic.%0 + + + + + MessageId: MF_E_NET_UNSUPPORTED_CONFIGURATION + + MessageText: + + The specified configuration value is not supported.%0 + + + + + MessageId: MF_E_NET_PROTOCOL_DISABLED + + MessageText: + + The networking protocol is disabled.%0 + + + + + MessageId: MF_E_ALREADY_INITIALIZED + + MessageText: + + This object has already been initialized and cannot be re-initialized at this time.%0 + + + + + MessageId: MF_E_BANDWIDTH_OVERRUN + + MessageText: + + The amount of data passed in exceeds the given bitrate and buffer window.%0 + + + + + MessageId: MF_E_LATE_SAMPLE + + MessageText: + + The sample was passed in too late to be correctly processed.%0 + + + + + MessageId: MF_E_FLUSH_NEEDED + + MessageText: + + The requested action cannot be carried out until the object is flushed and the queue is emptied.%0 + + + + + MessageId: MF_E_INVALID_PROFILE + + MessageText: + + The profile is invalid.%0 + + + + + MessageId: MF_E_INDEX_NOT_COMMITTED + + MessageText: + + The index that is being generated needs to be committed before the requested action can be carried out.%0 + + + + + MessageId: MF_E_NO_INDEX + + MessageText: + + The index that is necessary for the requested action is not found.%0 + + + + + MessageId: MF_E_CANNOT_INDEX_IN_PLACE + + MessageText: + + The requested index cannot be added in-place to the specified ASF content.%0 + + + + + MessageId: MF_E_MISSING_ASF_LEAKYBUCKET + + MessageText: + + The ASF leaky bucket parameters must be specified in order to carry out this request.%0 + + + + + MessageId: MF_E_INVALID_ASF_STREAMID + + MessageText: + + The stream id is invalid. The valid range for ASF stream id is from 1 to 127.%0 + + + + + MessageId: MF_E_STREAMSINK_REMOVED + + MessageText: + + The requested Stream Sink has been removed and cannot be used.%0 + + + + + MessageId: MF_E_STREAMSINKS_OUT_OF_SYNC + + MessageText: + + The various Stream Sinks in this Media Sink are too far out of sync for the requested action to take place.%0 + + + + + MessageId: MF_E_STREAMSINKS_FIXED + + MessageText: + + Stream Sinks cannot be added to or removed from this Media Sink because its set of streams is fixed.%0 + + + + + MessageId: MF_E_STREAMSINK_EXISTS + + MessageText: + + The given Stream Sink already exists.%0 + + + + + MessageId: MF_E_SAMPLEALLOCATOR_CANCELED + + MessageText: + + Sample allocations have been canceled.%0 + + + + + MessageId: MF_E_SAMPLEALLOCATOR_EMPTY + + MessageText: + + The sample allocator is currently empty, due to outstanding requests.%0 + + + + + MessageId: MF_E_SINK_ALREADYSTOPPED + + MessageText: + + When we try to sopt a stream sink, it is already stopped %0 + + + + + MessageId: MF_E_ASF_FILESINK_BITRATE_UNKNOWN + + MessageText: + + The ASF file sink could not reserve AVIO because the bitrate is unknown.%0 + + + + + MessageId: MF_E_SINK_NO_STREAMS + + MessageText: + + No streams are selected in sink presentation descriptor.%0 + + + + + MessageId: MF_S_SINK_NOT_FINALIZED + + MessageText: + + The sink has not been finalized before shut down. This may cause sink generate a corrupted content.%0 + + + + + MessageId: MF_E_METADATA_TOO_LONG + + MessageText: + + A metadata item was too long to write to the output container.%0 + + + + + MessageId: MF_E_SINK_NO_SAMPLES_PROCESSED + + MessageText: + + The operation failed because no samples were processed by the sink.%0 + + + + + MessageId: MF_E_VIDEO_REN_NO_PROCAMP_HW + + MessageText: + + There is no available procamp hardware with which to perform color correction.%0 + + + + + MessageId: MF_E_VIDEO_REN_NO_DEINTERLACE_HW + + MessageText: + + There is no available deinterlacing hardware with which to deinterlace the video stream.%0 + + + + + MessageId: MF_E_VIDEO_REN_COPYPROT_FAILED + + MessageText: + + A video stream requires copy protection to be enabled, but there was a failure in attempting to enable copy protection.%0 + + + + + MessageId: MF_E_VIDEO_REN_SURFACE_NOT_SHARED + + MessageText: + + A component is attempting to access a surface for sharing that is not shared.%0 + + + + + MessageId: MF_E_VIDEO_DEVICE_LOCKED + + MessageText: + + A component is attempting to access a shared device that is already locked by another component.%0 + + + + + MessageId: MF_E_NEW_VIDEO_DEVICE + + MessageText: + + The device is no longer available. The handle should be closed and a new one opened.%0 + + + + + MessageId: MF_E_NO_VIDEO_SAMPLE_AVAILABLE + + MessageText: + + A video sample is not currently queued on a stream that is required for mixing.%0 + + + + + MessageId: MF_E_NO_AUDIO_PLAYBACK_DEVICE + + MessageText: + + No audio playback device was found.%0 + + + + + MessageId: MF_E_AUDIO_PLAYBACK_DEVICE_IN_USE + + MessageText: + + The requested audio playback device is currently in use.%0 + + + + + MessageId: MF_E_AUDIO_PLAYBACK_DEVICE_INVALIDATED + + MessageText: + + The audio playback device is no longer present.%0 + + + + + MessageId: MF_E_AUDIO_SERVICE_NOT_RUNNING + + MessageText: + + The audio service is not running.%0 + + + + + MessageId: MF_E_TOPO_INVALID_OPTIONAL_NODE + + MessageText: + + The topology contains an invalid optional node. Possible reasons are incorrect number of outputs and inputs or optional node is at the beginning or end of a segment. %0 + + + + + MessageId: MF_E_TOPO_CANNOT_FIND_DECRYPTOR + + MessageText: + + No suitable transform was found to decrypt the content. %0 + + + + + MessageId: MF_E_TOPO_CODEC_NOT_FOUND + + MessageText: + + No suitable transform was found to encode or decode the content. %0 + + + + + MessageId: MF_E_TOPO_CANNOT_CONNECT + + MessageText: + + Unable to find a way to connect nodes%0 + + + + + MessageId: MF_E_TOPO_UNSUPPORTED + + MessageText: + + Unsupported operations in topoloader%0 + + + + + MessageId: MF_E_TOPO_INVALID_TIME_ATTRIBUTES + + MessageText: + + The topology or its nodes contain incorrectly set time attributes%0 + + + + + MessageId: MF_E_TOPO_LOOPS_IN_TOPOLOGY + + MessageText: + + The topology contains loops, which are unsupported in media foundation topologies%0 + + + + + MessageId: MF_E_TOPO_MISSING_PRESENTATION_DESCRIPTOR + + MessageText: + + A source stream node in the topology does not have a presentation descriptor%0 + + + + + MessageId: MF_E_TOPO_MISSING_STREAM_DESCRIPTOR + + MessageText: + + A source stream node in the topology does not have a stream descriptor%0 + + + + + MessageId: MF_E_TOPO_STREAM_DESCRIPTOR_NOT_SELECTED + + MessageText: + + A stream descriptor was set on a source stream node but it was not selected on the presentation descriptor%0 + + + + + MessageId: MF_E_TOPO_MISSING_SOURCE + + MessageText: + + A source stream node in the topology does not have a source%0 + + + + + MessageId: MF_E_TOPO_SINK_ACTIVATES_UNSUPPORTED + + MessageText: + + The topology loader does not support sink activates on output nodes.%0 + + + + + MessageId: MF_E_SEQUENCER_UNKNOWN_SEGMENT_ID + + MessageText: + + The sequencer cannot find a segment with the given ID.%0\n. + + + + + MessageId: MF_S_SEQUENCER_CONTEXT_CANCELED + + MessageText: + + The context was canceled.%0\n. + + + + + MessageId: MF_E_NO_SOURCE_IN_CACHE + + MessageText: + + Cannot find source in source cache.%0\n. + + + + + MessageId: MF_S_SEQUENCER_SEGMENT_AT_END_OF_STREAM + + MessageText: + + Cannot update topology flags.%0\n. + + + + + MessageId: MF_E_TRANSFORM_TYPE_NOT_SET + + MessageText: + + A valid type has not been set for this stream or a stream that it depends on.%0 + + + + + MessageId: MF_E_TRANSFORM_STREAM_CHANGE + + MessageText: + + A stream change has occurred. Output cannot be produced until the streams have been renegotiated.%0 + + + + + MessageId: MF_E_TRANSFORM_INPUT_REMAINING + + MessageText: + + The transform cannot take the requested action until all of the input data it currently holds is processed or flushed.%0 + + + + + MessageId: MF_E_TRANSFORM_PROFILE_MISSING + + MessageText: + + The transform requires a profile but no profile was supplied or found.%0 + + + + + MessageId: MF_E_TRANSFORM_PROFILE_INVALID_OR_CORRUPT + + MessageText: + + The transform requires a profile but the supplied profile was invalid or corrupt.%0 + + + + + MessageId: MF_E_TRANSFORM_PROFILE_TRUNCATED + + MessageText: + + The transform requires a profile but the supplied profile ended unexpectedly while parsing.%0 + + + + + MessageId: MF_E_TRANSFORM_PROPERTY_PID_NOT_RECOGNIZED + + MessageText: + + The property ID does not match any property supported by the transform.%0 + + + + + MessageId: MF_E_TRANSFORM_PROPERTY_VARIANT_TYPE_WRONG + + MessageText: + + The variant does not have the type expected for this property ID.%0 + + + + + MessageId: MF_E_TRANSFORM_PROPERTY_NOT_WRITEABLE + + MessageText: + + An attempt was made to set the value on a read-only property.%0 + + + + + MessageId: MF_E_TRANSFORM_PROPERTY_ARRAY_VALUE_WRONG_NUM_DIM + + MessageText: + + The array property value has an unexpected number of dimensions.%0 + + + + + MessageId: MF_E_TRANSFORM_PROPERTY_VALUE_SIZE_WRONG + + MessageText: + + The array or blob property value has an unexpected size.%0 + + + + + MessageId: MF_E_TRANSFORM_PROPERTY_VALUE_OUT_OF_RANGE + + MessageText: + + The property value is out of range for this transform.%0 + + + + + MessageId: MF_E_TRANSFORM_PROPERTY_VALUE_INCOMPATIBLE + + MessageText: + + The property value is incompatible with some other property or mediatype set on the transform.%0 + + + + + MessageId: MF_E_TRANSFORM_NOT_POSSIBLE_FOR_CURRENT_OUTPUT_MEDIATYPE + + MessageText: + + The requested operation is not supported for the currently set output mediatype.%0 + + + + + MessageId: MF_E_TRANSFORM_NOT_POSSIBLE_FOR_CURRENT_INPUT_MEDIATYPE + + MessageText: + + The requested operation is not supported for the currently set input mediatype.%0 + + + + + MessageId: MF_E_TRANSFORM_NOT_POSSIBLE_FOR_CURRENT_MEDIATYPE_COMBINATION + + MessageText: + + The requested operation is not supported for the currently set combination of mediatypes.%0 + + + + + MessageId: MF_E_TRANSFORM_CONFLICTS_WITH_OTHER_CURRENTLY_ENABLED_FEATURES + + MessageText: + + The requested feature is not supported in combination with some other currently enabled feature.%0 + + + + + MessageId: MF_E_TRANSFORM_NEED_MORE_INPUT + + MessageText: + + The transform cannot produce output until it gets more input samples.%0 + + + + + MessageId: MF_E_TRANSFORM_NOT_POSSIBLE_FOR_CURRENT_SPKR_CONFIG + + MessageText: + + The requested operation is not supported for the current speaker configuration.%0 + + + + + MessageId: MF_E_TRANSFORM_CANNOT_CHANGE_MEDIATYPE_WHILE_PROCESSING + + MessageText: + + The transform cannot accept mediatype changes in the middle of processing.%0 + + + + + MessageId: MF_S_TRANSFORM_DO_NOT_PROPAGATE_EVENT + + MessageText: + + The caller should not propagate this event to downstream components.%0 + + + + + MessageId: MF_E_UNSUPPORTED_D3D_TYPE + + MessageText: + + The input type is not supported for D3D device.%0 + + + + + MessageId: MF_E_TRANSFORM_ASYNC_LOCKED + + MessageText: + + The caller does not appear to support this transform's asynchronous capabilities.%0 + + + + + MessageId: MF_E_TRANSFORM_CANNOT_INITIALIZE_ACM_DRIVER + + MessageText: + + An audio compression manager driver could not be initialized by the transform.%0 + + + + + MessageId: MF_E_LICENSE_INCORRECT_RIGHTS + + MessageText: + + You are not allowed to open this file. Contact the content provider for further assistance.%0 + + + + + MessageId: MF_E_LICENSE_OUTOFDATE + + MessageText: + + The license for this media file has expired. Get a new license or contact the content provider for further assistance.%0 + + + + + MessageId: MF_E_LICENSE_REQUIRED + + MessageText: + + You need a license to perform the requested operation on this media file.%0 + + + + + MessageId: MF_E_DRM_HARDWARE_INCONSISTENT + + MessageText: + + The licenses for your media files are corrupted. Contact Microsoft product support.%0 + + + + + MessageId: MF_E_NO_CONTENT_PROTECTION_MANAGER + + MessageText: + + The APP needs to provide IMFContentProtectionManager callback to access the protected media file.%0 + + + + + MessageId: MF_E_LICENSE_RESTORE_NO_RIGHTS + + MessageText: + + Client does not have rights to restore licenses.%0 + + + + + MessageId: MF_E_BACKUP_RESTRICTED_LICENSE + + MessageText: + + Licenses are restricted and hence can not be backed up.%0 + + + + + MessageId: MF_E_LICENSE_RESTORE_NEEDS_INDIVIDUALIZATION + + MessageText: + + License restore requires machine to be individualized.%0 + + + + + MessageId: MF_S_PROTECTION_NOT_REQUIRED + + MessageText: + + Protection for stream is not required.%0 + + + + + MessageId: MF_E_COMPONENT_REVOKED + + MessageText: + + Component is revoked.%0 + + + + + MessageId: MF_E_TRUST_DISABLED + + MessageText: + + Trusted functionality is currently disabled on this component.%0 + + + + + MessageId: MF_E_WMDRMOTA_NO_ACTION + + MessageText: + + No Action is set on WMDRM Output Trust Authority.%0 + + + + + MessageId: MF_E_WMDRMOTA_ACTION_ALREADY_SET + + MessageText: + + Action is already set on WMDRM Output Trust Authority.%0 + + + + + MessageId: MF_E_WMDRMOTA_DRM_HEADER_NOT_AVAILABLE + + MessageText: + + DRM Heaader is not available.%0 + + + + + MessageId: MF_E_WMDRMOTA_DRM_ENCRYPTION_SCHEME_NOT_SUPPORTED + + MessageText: + + Current encryption scheme is not supported.%0 + + + + + MessageId: MF_E_WMDRMOTA_ACTION_MISMATCH + + MessageText: + + Action does not match with current configuration.%0 + + + + + MessageId: MF_E_WMDRMOTA_INVALID_POLICY + + MessageText: + + Invalid policy for WMDRM Output Trust Authority.%0 + + + + + MessageId: MF_E_POLICY_UNSUPPORTED + + MessageText: + + The policies that the Input Trust Authority requires to be enforced are unsupported by the outputs.%0 + + + + + MessageId: MF_E_OPL_NOT_SUPPORTED + + MessageText: + + The OPL that the license requires to be enforced are not supported by the Input Trust Authority.%0 + + + + + MessageId: MF_E_TOPOLOGY_VERIFICATION_FAILED + + MessageText: + + The topology could not be successfully verified.%0 + + + + + MessageId: MF_E_SIGNATURE_VERIFICATION_FAILED + + MessageText: + + Signature verification could not be completed successfully for this component.%0 + + + + + MessageId: MF_E_DEBUGGING_NOT_ALLOWED + + MessageText: + + Running this process under a debugger while using protected content is not allowed.%0 + + + + + MessageId: MF_E_CODE_EXPIRED + + MessageText: + + MF component has expired.%0 + + + + + MessageId: MF_E_GRL_VERSION_TOO_LOW + + MessageText: + + The current GRL on the machine does not meet the minimum version requirements.%0 + + + + + MessageId: MF_E_GRL_RENEWAL_NOT_FOUND + + MessageText: + + The current GRL on the machine does not contain any renewal entries for the specified revocation.%0 + + + + + MessageId: MF_E_GRL_EXTENSIBLE_ENTRY_NOT_FOUND + + MessageText: + + The current GRL on the machine does not contain any extensible entries for the specified extension GUID.%0 + + + + + MessageId: MF_E_KERNEL_UNTRUSTED + + MessageText: + + The kernel isn't secure for high security level content.%0 + + + + + MessageId: MF_E_PEAUTH_UNTRUSTED + + MessageText: + + The response from protected environment driver isn't valid.%0 + + + + + MessageId: MF_E_NON_PE_PROCESS + + MessageText: + + A non-PE process tried to talk to PEAuth.%0 + + + + + MessageId: MF_E_REBOOT_REQUIRED + + MessageText: + + We need to reboot the machine.%0 + + + + + MessageId: MF_S_WAIT_FOR_POLICY_SET + + MessageText: + + Protection for this stream is not guaranteed to be enforced until the MEPolicySet event is fired.%0 + + + + + MessageId: MF_S_VIDEO_DISABLED_WITH_UNKNOWN_SOFTWARE_OUTPUT + + MessageText: + + This video stream is disabled because it is being sent to an unknown software output.%0 + + + + + MessageId: MF_E_GRL_INVALID_FORMAT + + MessageText: + + The GRL file is not correctly formed, it may have been corrupted or overwritten.%0 + + + + + MessageId: MF_E_GRL_UNRECOGNIZED_FORMAT + + MessageText: + + The GRL file is in a format newer than those recognized by this GRL Reader.%0 + + + + + MessageId: MF_E_ALL_PROCESS_RESTART_REQUIRED + + MessageText: + + The GRL was reloaded and required all processes that can run protected media to restart.%0 + + + + + MessageId: MF_E_PROCESS_RESTART_REQUIRED + + MessageText: + + The GRL was reloaded and the current process needs to restart.%0 + + + + + MessageId: MF_E_USERMODE_UNTRUSTED + + MessageText: + + The user space is untrusted for protected content play.%0 + + + + + MessageId: MF_E_PEAUTH_SESSION_NOT_STARTED + + MessageText: + + PEAuth communication session hasn't been started.%0 + + + + + MessageId: MF_E_PEAUTH_PUBLICKEY_REVOKED + + MessageText: + + PEAuth's public key is revoked.%0 + + + + + MessageId: MF_E_GRL_ABSENT + + MessageText: + + The GRL is absent.%0 + + + + + MessageId: MF_S_PE_TRUSTED + + MessageText: + + The Protected Environment is trusted.%0 + + + + + MessageId: MF_E_PE_UNTRUSTED + + MessageText: + + The Protected Environment is untrusted.%0 + + + + + MessageId: MF_E_PEAUTH_NOT_STARTED + + MessageText: + + The Protected Environment Authorization service (PEAUTH) has not been started.%0 + + + + + MessageId: MF_E_INCOMPATIBLE_SAMPLE_PROTECTION + + MessageText: + + The sample protection algorithms supported by components are not compatible.%0 + + + + + MessageId: MF_E_PE_SESSIONS_MAXED + + MessageText: + + No more protected environment sessions can be supported.%0 + + + + + MessageId: MF_E_HIGH_SECURITY_LEVEL_CONTENT_NOT_ALLOWED + + MessageText: + + WMDRM ITA does not allow protected content with high security level for this release.%0 + + + + + MessageId: MF_E_TEST_SIGNED_COMPONENTS_NOT_ALLOWED + + MessageText: + + WMDRM ITA cannot allow the requested action for the content as one or more components is not properly signed.%0 + + + + + MessageId: MF_E_ITA_UNSUPPORTED_ACTION + + MessageText: + + WMDRM ITA does not support the requested action.%0 + + + + + MessageId: MF_E_ITA_ERROR_PARSING_SAP_PARAMETERS + + MessageText: + + WMDRM ITA encountered an error in parsing the Secure Audio Path parameters.%0 + + + + + MessageId: MF_E_POLICY_MGR_ACTION_OUTOFBOUNDS + + MessageText: + + The Policy Manager action passed in is invalid.%0 + + + + + MessageId: MF_E_BAD_OPL_STRUCTURE_FORMAT + + MessageText: + + The structure specifying Output Protection Level is not the correct format.%0 + + + + + MessageId: MF_E_ITA_UNRECOGNIZED_ANALOG_VIDEO_PROTECTION_GUID + + MessageText: + + WMDRM ITA does not recognize the Explicite Analog Video Output Protection guid specified in the license.%0 + + + + + MessageId: MF_E_NO_PMP_HOST + + MessageText: + + IMFPMPHost object not available.%0 + + + + + MessageId: MF_E_ITA_OPL_DATA_NOT_INITIALIZED + + MessageText: + + WMDRM ITA could not initialize the Output Protection Level data.%0 + + + + + MessageId: MF_E_ITA_UNRECOGNIZED_ANALOG_VIDEO_OUTPUT + + MessageText: + + WMDRM ITA does not recognize the Analog Video Output specified by the OTA.%0 + + + + + MessageId: MF_E_ITA_UNRECOGNIZED_DIGITAL_VIDEO_OUTPUT + + MessageText: + + WMDRM ITA does not recognize the Digital Video Output specified by the OTA.%0 + + + + + MessageId: MF_E_CLOCK_INVALID_CONTINUITY_KEY + + MessageText: + + The continuity key supplied is not currently valid.%0 + + + + + MessageId: MF_E_CLOCK_NO_TIME_SOURCE + + MessageText: + + No Presentation Time Source has been specified.%0 + + + + + MessageId: MF_E_CLOCK_STATE_ALREADY_SET + + MessageText: + + The clock is already in the requested state.%0 + + + + + MessageId: MF_E_CLOCK_NOT_SIMPLE + + MessageText: + + The clock has too many advanced features to carry out the request.%0 + + + + + MessageId: MF_S_CLOCK_STOPPED + + MessageText: + + Timer::SetTimer returns this success code if called happened while timer is stopped. Timer is not going to be dispatched until clock is running%0 + + + + + MessageId: MF_E_NO_MORE_DROP_MODES + + MessageText: + + The component does not support any more drop modes.%0 + + + + + MessageId: MF_E_NO_MORE_QUALITY_LEVELS + + MessageText: + + The component does not support any more quality levels.%0 + + + + + MessageId: MF_E_DROPTIME_NOT_SUPPORTED + + MessageText: + + The component does not support drop time functionality.%0 + + + + + MessageId: MF_E_QUALITYKNOB_WAIT_LONGER + + MessageText: + + Quality Manager needs to wait longer before bumping the Quality Level up.%0 + + + + + MessageId: MF_E_QM_INVALIDSTATE + + MessageText: + + Quality Manager is in an invalid state. Quality Management is off at this moment.%0 + + + + + MessageId: MF_E_TRANSCODE_NO_CONTAINERTYPE + + MessageText: + + No transcode output container type is specified.%0 + + + + + MessageId: MF_E_TRANSCODE_PROFILE_NO_MATCHING_STREAMS + + MessageText: + + The profile does not have a media type configuration for any selected source streams.%0 + + + + + MessageId: MF_E_TRANSCODE_NO_MATCHING_ENCODER + + MessageText: + + Cannot find an encoder MFT that accepts the user preferred output type.%0 + + + + + MessageId: MF_E_ALLOCATOR_NOT_INITIALIZED + + MessageText: + + Memory allocator is not initialized.%0 + + + + + MessageId: MF_E_ALLOCATOR_NOT_COMMITED + + MessageText: + + Memory allocator is not committed yet.%0 + + + + + MessageId: MF_E_ALLOCATOR_ALREADY_COMMITED + + MessageText: + + Memory allocator has already been committed.%0 + + + + + MessageId: MF_E_STREAM_ERROR + + MessageText: + + An error occurred in media stream.%0 + + + + + MessageId: MF_E_INVALID_STREAM_STATE + + MessageText: + + Stream is not in a state to handle the request.%0 + + + + + MessageId: MF_E_HW_STREAM_NOT_CONNECTED + + MessageText: + + Hardware stream is not connected yet.%0 + + + + + Major Media Types + http://msdn.microsoft.com/en-us/library/windows/desktop/aa367377%28v=vs.85%29.aspx + + + + + Default + + + + + Audio + + + + + Video + + + + + Protected Media + + + + + Synchronized Accessible Media Interchange (SAMI) captions. + + + + + Script stream + + + + + Still image stream. + + + + + HTML stream. + + + + + Binary stream. + + + + + A stream that contains data files. + + + + + IMFActivate, defined in mfobjects.h + + + + + Retrieves the value associated with a key. + + + + + Retrieves the data type of the value associated with a key. + + + + + Queries whether a stored attribute value equals a specified PROPVARIANT. + + + + + Compares the attributes on this object with the attributes on another object. + + + + + Retrieves a UINT32 value associated with a key. + + + + + Retrieves a UINT64 value associated with a key. + + + + + Retrieves a double value associated with a key. + + + + + Retrieves a GUID value associated with a key. + + + + + Retrieves the length of a string value associated with a key. + + + + + Retrieves a wide-character string associated with a key. + + + + + Retrieves a wide-character string associated with a key. This method allocates the memory for the string. + + + + + Retrieves the length of a byte array associated with a key. + + + + + Retrieves a byte array associated with a key. + + + + + Retrieves a byte array associated with a key. This method allocates the memory for the array. + + + + + Retrieves an interface pointer associated with a key. + + + + + Associates an attribute value with a key. + + + + + Removes a key/value pair from the object's attribute list. + + + + + Removes all key/value pairs from the object's attribute list. + + + + + Associates a UINT32 value with a key. + + + + + Associates a UINT64 value with a key. + + + + + Associates a double value with a key. + + + + + Associates a GUID value with a key. + + + + + Associates a wide-character string with a key. + + + + + Associates a byte array with a key. + + + + + Associates an IUnknown pointer with a key. + + + + + Locks the attribute store so that no other thread can access it. + + + + + Unlocks the attribute store. + + + + + Retrieves the number of attributes that are set on this object. + + + + + Retrieves an attribute at the specified index. + + + + + Copies all of the attributes from this object into another attribute store. + + + + + Creates the object associated with this activation object. + + + + + Shuts down the created object. + + + + + Detaches the created object from the activation object. + + + + + Represents a generic collection of IUnknown pointers. + + + + + Retrieves the number of objects in the collection. + + + + + Retrieves an object in the collection. + + + + + Adds an object to the collection. + + + + + Removes an object from the collection. + + + + + Removes an object from the collection. + + + + + Removes all items from the collection. + + + + + IMFMediaEvent - Represents an event generated by a Media Foundation object. Use this interface to get information about the event. + http://msdn.microsoft.com/en-us/library/windows/desktop/ms702249%28v=vs.85%29.aspx + Mfobjects.h + + + + + Retrieves the value associated with a key. + + + + + Retrieves the data type of the value associated with a key. + + + + + Queries whether a stored attribute value equals a specified PROPVARIANT. + + + + + Compares the attributes on this object with the attributes on another object. + + + + + Retrieves a UINT32 value associated with a key. + + + + + Retrieves a UINT64 value associated with a key. + + + + + Retrieves a double value associated with a key. + + + + + Retrieves a GUID value associated with a key. + + + + + Retrieves the length of a string value associated with a key. + + + + + Retrieves a wide-character string associated with a key. + + + + + Retrieves a wide-character string associated with a key. This method allocates the memory for the string. + + + + + Retrieves the length of a byte array associated with a key. + + + + + Retrieves a byte array associated with a key. + + + + + Retrieves a byte array associated with a key. This method allocates the memory for the array. + + + + + Retrieves an interface pointer associated with a key. + + + + + Associates an attribute value with a key. + + + + + Removes a key/value pair from the object's attribute list. + + + + + Removes all key/value pairs from the object's attribute list. + + + + + Associates a UINT32 value with a key. + + + + + Associates a UINT64 value with a key. + + + + + Associates a double value with a key. + + + + + Associates a GUID value with a key. + + + + + Associates a wide-character string with a key. + + + + + Associates a byte array with a key. + + + + + Associates an IUnknown pointer with a key. + + + + + Locks the attribute store so that no other thread can access it. + + + + + Unlocks the attribute store. + + + + + Retrieves the number of attributes that are set on this object. + + + + + Retrieves an attribute at the specified index. + + + + + Copies all of the attributes from this object into another attribute store. + + + + + Retrieves the event type. + + + virtual HRESULT STDMETHODCALLTYPE GetType( + /* [out] */ __RPC__out MediaEventType *pmet) = 0; + + + + + Retrieves the extended type of the event. + + + virtual HRESULT STDMETHODCALLTYPE GetExtendedType( + /* [out] */ __RPC__out GUID *pguidExtendedType) = 0; + + + + + Retrieves an HRESULT that specifies the event status. + + + virtual HRESULT STDMETHODCALLTYPE GetStatus( + /* [out] */ __RPC__out HRESULT *phrStatus) = 0; + + + + + Retrieves the value associated with the event, if any. + + + virtual HRESULT STDMETHODCALLTYPE GetValue( + /* [out] */ __RPC__out PROPVARIANT *pvValue) = 0; + + + + + Implemented by the Microsoft Media Foundation sink writer object. + + + + + Adds a stream to the sink writer. + + + + + Sets the input format for a stream on the sink writer. + + + + + Initializes the sink writer for writing. + + + + + Delivers a sample to the sink writer. + + + + + Indicates a gap in an input stream. + + + + + Places a marker in the specified stream. + + + + + Notifies the media sink that a stream has reached the end of a segment. + + + + + Flushes one or more streams. + + + + + (Finalize) Completes all writing operations on the sink writer. + + + + + Queries the underlying media sink or encoder for an interface. + + + + + Gets statistics about the performance of the sink writer. + + + + + IMFTransform, defined in mftransform.h + + + + + Retrieves the minimum and maximum number of input and output streams. + + + virtual HRESULT STDMETHODCALLTYPE GetStreamLimits( + /* [out] */ __RPC__out DWORD *pdwInputMinimum, + /* [out] */ __RPC__out DWORD *pdwInputMaximum, + /* [out] */ __RPC__out DWORD *pdwOutputMinimum, + /* [out] */ __RPC__out DWORD *pdwOutputMaximum) = 0; + + + + + Retrieves the current number of input and output streams on this MFT. + + + virtual HRESULT STDMETHODCALLTYPE GetStreamCount( + /* [out] */ __RPC__out DWORD *pcInputStreams, + /* [out] */ __RPC__out DWORD *pcOutputStreams) = 0; + + + + + Retrieves the stream identifiers for the input and output streams on this MFT. + + + virtual HRESULT STDMETHODCALLTYPE GetStreamIDs( + DWORD dwInputIDArraySize, + /* [size_is][out] */ __RPC__out_ecount_full(dwInputIDArraySize) DWORD *pdwInputIDs, + DWORD dwOutputIDArraySize, + /* [size_is][out] */ __RPC__out_ecount_full(dwOutputIDArraySize) DWORD *pdwOutputIDs) = 0; + + + + + Gets the buffer requirements and other information for an input stream on this Media Foundation transform (MFT). + + + virtual HRESULT STDMETHODCALLTYPE GetInputStreamInfo( + DWORD dwInputStreamID, + /* [out] */ __RPC__out MFT_INPUT_STREAM_INFO *pStreamInfo) = 0; + + + + + Gets the buffer requirements and other information for an output stream on this Media Foundation transform (MFT). + + + virtual HRESULT STDMETHODCALLTYPE GetOutputStreamInfo( + DWORD dwOutputStreamID, + /* [out] */ __RPC__out MFT_OUTPUT_STREAM_INFO *pStreamInfo) = 0; + + + + + Gets the global attribute store for this Media Foundation transform (MFT). + + + virtual HRESULT STDMETHODCALLTYPE GetAttributes( + /* [out] */ __RPC__deref_out_opt IMFAttributes **pAttributes) = 0; + + + + + Retrieves the attribute store for an input stream on this MFT. + + + virtual HRESULT STDMETHODCALLTYPE GetInputStreamAttributes( + DWORD dwInputStreamID, + /* [out] */ __RPC__deref_out_opt IMFAttributes **pAttributes) = 0; + + + + + Retrieves the attribute store for an output stream on this MFT. + + + virtual HRESULT STDMETHODCALLTYPE GetOutputStreamAttributes( + DWORD dwOutputStreamID, + /* [out] */ __RPC__deref_out_opt IMFAttributes **pAttributes) = 0; + + + + + Removes an input stream from this MFT. + + + virtual HRESULT STDMETHODCALLTYPE DeleteInputStream( + DWORD dwStreamID) = 0; + + + + + Adds one or more new input streams to this MFT. + + + virtual HRESULT STDMETHODCALLTYPE AddInputStreams( + DWORD cStreams, + /* [in] */ __RPC__in DWORD *adwStreamIDs) = 0; + + + + + Gets an available media type for an input stream on this Media Foundation transform (MFT). + + + virtual HRESULT STDMETHODCALLTYPE GetInputAvailableType( + DWORD dwInputStreamID, + DWORD dwTypeIndex, + /* [out] */ __RPC__deref_out_opt IMFMediaType **ppType) = 0; + + + + + Retrieves an available media type for an output stream on this MFT. + + + virtual HRESULT STDMETHODCALLTYPE GetOutputAvailableType( + DWORD dwOutputStreamID, + DWORD dwTypeIndex, + /* [out] */ __RPC__deref_out_opt IMFMediaType **ppType) = 0; + + + + + Sets, tests, or clears the media type for an input stream on this Media Foundation transform (MFT). + + + virtual HRESULT STDMETHODCALLTYPE SetInputType( + DWORD dwInputStreamID, + /* [in] */ __RPC__in_opt IMFMediaType *pType, + DWORD dwFlags) = 0; + + + + + Sets, tests, or clears the media type for an output stream on this Media Foundation transform (MFT). + + + virtual HRESULT STDMETHODCALLTYPE SetOutputType( + DWORD dwOutputStreamID, + /* [in] */ __RPC__in_opt IMFMediaType *pType, + DWORD dwFlags) = 0; + + + + + Gets the current media type for an input stream on this Media Foundation transform (MFT). + + + virtual HRESULT STDMETHODCALLTYPE GetInputCurrentType( + DWORD dwInputStreamID, + /* [out] */ __RPC__deref_out_opt IMFMediaType **ppType) = 0; + + + + + Gets the current media type for an output stream on this Media Foundation transform (MFT). + + + virtual HRESULT STDMETHODCALLTYPE GetOutputCurrentType( + DWORD dwOutputStreamID, + /* [out] */ __RPC__deref_out_opt IMFMediaType **ppType) = 0; + + + + + Queries whether an input stream on this Media Foundation transform (MFT) can accept more data. + + + virtual HRESULT STDMETHODCALLTYPE GetInputStatus( + DWORD dwInputStreamID, + /* [out] */ __RPC__out DWORD *pdwFlags) = 0; + + + + + Queries whether the Media Foundation transform (MFT) is ready to produce output data. + + + virtual HRESULT STDMETHODCALLTYPE GetOutputStatus( + /* [out] */ __RPC__out DWORD *pdwFlags) = 0; + + + + + Sets the range of time stamps the client needs for output. + + + virtual HRESULT STDMETHODCALLTYPE SetOutputBounds( + LONGLONG hnsLowerBound, + LONGLONG hnsUpperBound) = 0; + + + + + Sends an event to an input stream on this Media Foundation transform (MFT). + + + virtual HRESULT STDMETHODCALLTYPE ProcessEvent( + DWORD dwInputStreamID, + /* [in] */ __RPC__in_opt IMFMediaEvent *pEvent) = 0; + + + + + Sends a message to the Media Foundation transform (MFT). + + + virtual HRESULT STDMETHODCALLTYPE ProcessMessage( + MFT_MESSAGE_TYPE eMessage, + ULONG_PTR ulParam) = 0; + + + + + Delivers data to an input stream on this Media Foundation transform (MFT). + + + virtual /* [local] */ HRESULT STDMETHODCALLTYPE ProcessInput( + DWORD dwInputStreamID, + IMFSample *pSample, + DWORD dwFlags) = 0; + + + + + Generates output from the current input data. + + + virtual /* [local] */ HRESULT STDMETHODCALLTYPE ProcessOutput( + DWORD dwFlags, + DWORD cOutputBufferCount, + /* [size_is][out][in] */ MFT_OUTPUT_DATA_BUFFER *pOutputSamples, + /* [out] */ DWORD *pdwStatus) = 0; + + + + + See mfobjects.h + + + + + Unknown event type. + + + + + Signals a serious error. + + + + + Custom event type. + + + + + A non-fatal error occurred during streaming. + + + + + Session Unknown + + + + + Raised after the IMFMediaSession::SetTopology method completes asynchronously + + + + + Raised by the Media Session when the IMFMediaSession::ClearTopologies method completes asynchronously. + + + + + Raised when the IMFMediaSession::Start method completes asynchronously. + + + + + Raised when the IMFMediaSession::Pause method completes asynchronously. + + + + + Raised when the IMFMediaSession::Stop method completes asynchronously. + + + + + Raised when the IMFMediaSession::Close method completes asynchronously. + + + + + Raised by the Media Session when it has finished playing the last presentation in the playback queue. + + + + + Raised by the Media Session when the playback rate changes. + + + + + Raised by the Media Session when it completes a scrubbing request. + + + + + Raised by the Media Session when the session capabilities change. + + + + + Raised by the Media Session when the status of a topology changes. + + + + + Raised by the Media Session when a new presentation starts. + + + + + Raised by a media source a new presentation is ready. + + + + + License acquisition is about to begin. + + + + + License acquisition is complete. + + + + + Individualization is about to begin. + + + + + Individualization is complete. + + + + + Signals the progress of a content enabler object. + + + + + A content enabler object's action is complete. + + + + + Raised by a trusted output if an error occurs while enforcing the output policy. + + + + + Contains status information about the enforcement of an output policy. + + + + + A media source started to buffer data. + + + + + A media source stopped buffering data. + + + + + The network source started opening a URL. + + + + + The network source finished opening a URL. + + + + + Raised by a media source at the start of a reconnection attempt. + + + + + Raised by a media source at the end of a reconnection attempt. + + + + + Raised by the enhanced video renderer (EVR) when it receives a user event from the presenter. + + + + + Raised by the Media Session when the format changes on a media sink. + + + + + Source Unknown + + + + + Raised when a media source starts without seeking. + + + + + Raised by a media stream when the source starts without seeking. + + + + + Raised when a media source seeks to a new position. + + + + + Raised by a media stream after a call to IMFMediaSource::Start causes a seek in the stream. + + + + + Raised by a media source when it starts a new stream. + + + + + Raised by a media source when it restarts or seeks a stream that is already active. + + + + + Raised by a media source when the IMFMediaSource::Stop method completes asynchronously. + + + + + Raised by a media stream when the IMFMediaSource::Stop method completes asynchronously. + + + + + Raised by a media source when the IMFMediaSource::Pause method completes asynchronously. + + + + + Raised by a media stream when the IMFMediaSource::Pause method completes asynchronously. + + + + + Raised by a media source when a presentation ends. + + + + + Raised by a media stream when the stream ends. + + + + + Raised when a media stream delivers a new sample. + + + + + Signals that a media stream does not have data available at a specified time. + + + + + Raised by a media stream when it starts or stops thinning the stream. + + + + + Raised by a media stream when the media type of the stream changes. + + + + + Raised by a media source when the playback rate changes. + + + + + Raised by the sequencer source when a segment is completed and is followed by another segment. + + + + + Raised by a media source when the source's characteristics change. + + + + + Raised by a media source to request a new playback rate. + + + + + Raised by a media source when it updates its metadata. + + + + + Raised by the sequencer source when the IMFSequencerSource::UpdateTopology method completes asynchronously. + + + + + Sink Unknown + + + + + Raised by a stream sink when it completes the transition to the running state. + + + + + Raised by a stream sink when it completes the transition to the stopped state. + + + + + Raised by a stream sink when it completes the transition to the paused state. + + + + + Raised by a stream sink when the rate has changed. + + + + + Raised by a stream sink to request a new media sample from the pipeline. + + + + + Raised by a stream sink after the IMFStreamSink::PlaceMarker method is called. + + + + + Raised by a stream sink when the stream has received enough preroll data to begin rendering. + + + + + Raised by a stream sink when it completes a scrubbing request. + + + + + Raised by a stream sink when the sink's media type is no longer valid. + + + + + Raised by the stream sinks of the EVR if the video device changes. + + + + + Provides feedback about playback quality to the quality manager. + + + + + Raised when a media sink becomes invalid. + + + + + The audio session display name changed. + + + + + The volume or mute state of the audio session changed + + + + + The audio device was removed. + + + + + The Windows audio server system was shut down. + + + + + The grouping parameters changed for the audio session. + + + + + The audio session icon changed. + + + + + The default audio format for the audio device changed. + + + + + The audio session was disconnected from a Windows Terminal Services session + + + + + The audio session was preempted by an exclusive-mode connection. + + + + + Trust Unknown + + + + + The output policy for a stream changed. + + + + + Content protection message + + + + + The IMFOutputTrustAuthority::SetPolicy method completed. + + + + + DRM License Backup Completed + + + + + DRM License Backup Progress + + + + + DRM License Restore Completed + + + + + DRM License Restore Progress + + + + + DRM License Acquisition Completed + + + + + DRM Individualization Completed + + + + + DRM Individualization Progress + + + + + DRM Proximity Completed + + + + + DRM License Store Cleaned + + + + + DRM Revocation Download Completed + + + + + Transform Unknown + + + + + Sent by an asynchronous MFT to request a new input sample. + + + + + Sent by an asynchronous MFT when new output data is available from the MFT. + + + + + Sent by an asynchronous Media Foundation transform (MFT) when a drain operation is complete. + + + + + Sent by an asynchronous MFT in response to an MFT_MESSAGE_COMMAND_MARKER message. + + + + + Media Foundation attribute guids + http://msdn.microsoft.com/en-us/library/windows/desktop/ms696989%28v=vs.85%29.aspx + + + + + Specifies whether an MFT performs asynchronous processing. + + + + + Enables the use of an asynchronous MFT. + + + + + Contains flags for an MFT activation object. + + + + + Specifies the category for an MFT. + + + + + Contains the class identifier (CLSID) of an MFT. + + + + + Contains the registered input types for a Media Foundation transform (MFT). + + + + + Contains the registered output types for a Media Foundation transform (MFT). + + + + + Contains the symbolic link for a hardware-based MFT. + + + + + Contains the display name for a hardware-based MFT. + + + + + Contains a pointer to the stream attributes of the connected stream on a hardware-based MFT. + + + + + Specifies whether a hardware-based MFT is connected to another hardware-based MFT. + + + + + Specifies the preferred output format for an encoder. + + + + + Specifies whether an MFT is registered only in the application's process. + + + + + Contains configuration properties for an encoder. + + + + + Specifies whether a hardware device source uses the system time for time stamps. + + + + + Contains an IMFFieldOfUseMFTUnlock pointer, which can be used to unlock the MFT. + + + + + Contains the merit value of a hardware codec. + + + + + Specifies whether a decoder is optimized for transcoding rather than for playback. + + + + + Contains a pointer to the proxy object for the application's presentation descriptor. + + + + + Contains a pointer to the presentation descriptor from the protected media path (PMP). + + + + + Specifies the duration of a presentation, in 100-nanosecond units. + + + + + Specifies the total size of the source file, in bytes. + + + + + Specifies the audio encoding bit rate for the presentation, in bits per second. + + + + + Specifies the video encoding bit rate for the presentation, in bits per second. + + + + + Specifies the MIME type of the content. + + + + + Specifies when a presentation was last modified. + + + + + The identifier of the playlist element in the presentation. + + + + + Contains the preferred RFC 1766 language of the media source. + + + + + The time at which the presentation must begin, relative to the start of the media source. + + + + + Specifies whether the audio streams in the presentation have a variable bit rate. + + + + + Media type Major Type + + + + + Media Type subtype + + + + + Audio block alignment + + + + + Audio average bytes per second + + + + + Audio number of channels + + + + + Audio samples per second + + + + + Audio bits per sample + + + + + Enables the source reader or sink writer to use hardware-based Media Foundation transforms (MFTs). + + + + + Contains additional format data for a media type. + + + + + Specifies for a media type whether each sample is independent of the other samples in the stream. + + + + + Specifies for a media type whether the samples have a fixed size. + + + + + Contains a DirectShow format GUID for a media type. + + + + + Specifies the preferred legacy format structure to use when converting an audio media type. + + + + + Specifies for a media type whether the media data is compressed. + + + + + Approximate data rate of the video stream, in bits per second, for a video media type. + + + + + Specifies the payload type of an Advanced Audio Coding (AAC) stream. + 0 - The stream contains raw_data_block elements only + 1 - Audio Data Transport Stream (ADTS). The stream contains an adts_sequence, as defined by MPEG-2. + 2 - Audio Data Interchange Format (ADIF). The stream contains an adif_sequence, as defined by MPEG-2. + 3 - The stream contains an MPEG-4 audio transport stream with a synchronization layer (LOAS) and a multiplex layer (LATM). + + + + + Specifies the audio profile and level of an Advanced Audio Coding (AAC) stream, as defined by ISO/IEC 14496-3. + + + + + Main interface for using Media Foundation with NAudio + + + + + initializes MediaFoundation - only needs to be called once per process + + + + + Enumerate the installed MediaFoundation transforms in the specified category + + A category from MediaFoundationTransformCategories + + + + + uninitializes MediaFoundation + + + + + Creates a Media type + + + + + Creates a media type from a WaveFormat + + + + + Creates a memory buffer of the specified size + + Memory buffer size in bytes + The memory buffer + + + + Creates a sample object + + The sample object + + + + Creates a new attributes store + + Initial size + The attributes store + + + + Creates a media foundation byte stream based on a stream object + (usable with WinRT streams) + + The input stream + A media foundation byte stream + + + + Creates a source reader based on a byte stream + + The byte stream + A media foundation source reader + + + + Interop definitions for MediaFoundation + thanks to Lucian Wischik for the initial work on many of these definitions (also various interfaces) + n.b. the goal is to make as much of this internal as possible, and provide + better .NET APIs using the MediaFoundationApi class instead + + + + + Initializes Microsoft Media Foundation. + + + + + Shuts down the Microsoft Media Foundation platform + + + + + Creates an empty media type. + + + + + Initializes a media type from a WAVEFORMATEX structure. + + + + + Converts a Media Foundation audio media type to a WAVEFORMATEX structure. + + TODO: try making second parameter out WaveFormatExtraData + + + + Creates the source reader from a URL. + + + + + Creates the source reader from a byte stream. + + + + + Creates the sink writer from a URL or byte stream. + + + + + Creates a Microsoft Media Foundation byte stream that wraps an IRandomAccessStream object. + + + + + Gets a list of Microsoft Media Foundation transforms (MFTs) that match specified search criteria. + + + + + Creates an empty media sample. + + + + + Allocates system memory and creates a media buffer to manage it. + + + + + Creates an empty attribute store. + + + + + Gets a list of output formats from an audio encoder. + + + + + All streams + + + + + First audio stream + + + + + First video stream + + + + + Media source + + + + + Media Foundation SDK Version + + + + + Media Foundation API Version + + + + + Media Foundation Version + + + + + Provides a generic way to store key/value pairs on an object. + http://msdn.microsoft.com/en-gb/library/windows/desktop/ms704598%28v=vs.85%29.aspx + + + + + Retrieves the value associated with a key. + + + + + Retrieves the data type of the value associated with a key. + + + + + Queries whether a stored attribute value equals a specified PROPVARIANT. + + + + + Compares the attributes on this object with the attributes on another object. + + + + + Retrieves a UINT32 value associated with a key. + + + + + Retrieves a UINT64 value associated with a key. + + + + + Retrieves a double value associated with a key. + + + + + Retrieves a GUID value associated with a key. + + + + + Retrieves the length of a string value associated with a key. + + + + + Retrieves a wide-character string associated with a key. + + + + + Retrieves a wide-character string associated with a key. This method allocates the memory for the string. + + + + + Retrieves the length of a byte array associated with a key. + + + + + Retrieves a byte array associated with a key. + + + + + Retrieves a byte array associated with a key. This method allocates the memory for the array. + + + + + Retrieves an interface pointer associated with a key. + + + + + Associates an attribute value with a key. + + + + + Removes a key/value pair from the object's attribute list. + + + + + Removes all key/value pairs from the object's attribute list. + + + + + Associates a UINT32 value with a key. + + + + + Associates a UINT64 value with a key. + + + + + Associates a double value with a key. + + + + + Associates a GUID value with a key. + + + + + Associates a wide-character string with a key. + + + + + Associates a byte array with a key. + + + + + Associates an IUnknown pointer with a key. + + + + + Locks the attribute store so that no other thread can access it. + + + + + Unlocks the attribute store. + + + + + Retrieves the number of attributes that are set on this object. + + + + + Retrieves an attribute at the specified index. + + + + + Copies all of the attributes from this object into another attribute store. + + + + + IMFByteStream + http://msdn.microsoft.com/en-gb/library/windows/desktop/ms698720%28v=vs.85%29.aspx + + + + + Retrieves the characteristics of the byte stream. + virtual HRESULT STDMETHODCALLTYPE GetCapabilities(/*[out]*/ __RPC__out DWORD *pdwCapabilities) = 0; + + + + + Retrieves the length of the stream. + virtual HRESULT STDMETHODCALLTYPE GetLength(/*[out]*/ __RPC__out QWORD *pqwLength) = 0; + + + + + Sets the length of the stream. + virtual HRESULT STDMETHODCALLTYPE SetLength(/*[in]*/ QWORD qwLength) = 0; + + + + + Retrieves the current read or write position in the stream. + virtual HRESULT STDMETHODCALLTYPE GetCurrentPosition(/*[out]*/ __RPC__out QWORD *pqwPosition) = 0; + + + + + Sets the current read or write position. + virtual HRESULT STDMETHODCALLTYPE SetCurrentPosition(/*[in]*/ QWORD qwPosition) = 0; + + + + + Queries whether the current position has reached the end of the stream. + virtual HRESULT STDMETHODCALLTYPE IsEndOfStream(/*[out]*/ __RPC__out BOOL *pfEndOfStream) = 0; + + + + + Reads data from the stream. + virtual HRESULT STDMETHODCALLTYPE Read(/*[size_is][out]*/ __RPC__out_ecount_full(cb) BYTE *pb, /*[in]*/ ULONG cb, /*[out]*/ __RPC__out ULONG *pcbRead) = 0; + + + + + Begins an asynchronous read operation from the stream. + virtual /*[local]*/ HRESULT STDMETHODCALLTYPE BeginRead(/*[out]*/ _Out_writes_bytes_(cb) BYTE *pb, /*[in]*/ ULONG cb, /*[in]*/ IMFAsyncCallback *pCallback, /*[in]*/ IUnknown *punkState) = 0; + + + + + Completes an asynchronous read operation. + virtual /*[local]*/ HRESULT STDMETHODCALLTYPE EndRead(/*[in]*/ IMFAsyncResult *pResult, /*[out]*/ _Out_ ULONG *pcbRead) = 0; + + + + + Writes data to the stream. + virtual HRESULT STDMETHODCALLTYPE Write(/*[size_is][in]*/ __RPC__in_ecount_full(cb) const BYTE *pb, /*[in]*/ ULONG cb, /*[out]*/ __RPC__out ULONG *pcbWritten) = 0; + + + + + Begins an asynchronous write operation to the stream. + virtual /*[local]*/ HRESULT STDMETHODCALLTYPE BeginWrite(/*[in]*/ _In_reads_bytes_(cb) const BYTE *pb, /*[in]*/ ULONG cb, /*[in]*/ IMFAsyncCallback *pCallback, /*[in]*/ IUnknown *punkState) = 0; + + + + + Completes an asynchronous write operation. + virtual /*[local]*/ HRESULT STDMETHODCALLTYPE EndWrite(/*[in]*/ IMFAsyncResult *pResult, /*[out]*/ _Out_ ULONG *pcbWritten) = 0; + + + + + Moves the current position in the stream by a specified offset. + virtual HRESULT STDMETHODCALLTYPE Seek(/*[in]*/ MFBYTESTREAM_SEEK_ORIGIN SeekOrigin, /*[in]*/ LONGLONG llSeekOffset, /*[in]*/ DWORD dwSeekFlags, /*[out]*/ __RPC__out QWORD *pqwCurrentPosition) = 0; + + + + + Clears any internal buffers used by the stream. + virtual HRESULT STDMETHODCALLTYPE Flush( void) = 0; + + + + + Closes the stream and releases any resources associated with the stream. + virtual HRESULT STDMETHODCALLTYPE Close( void) = 0; + + + + + IMFMediaBuffer + http://msdn.microsoft.com/en-gb/library/windows/desktop/ms696261%28v=vs.85%29.aspx + + + + + Gives the caller access to the memory in the buffer. + + + + + Unlocks a buffer that was previously locked. + + + + + Retrieves the length of the valid data in the buffer. + + + + + Sets the length of the valid data in the buffer. + + + + + Retrieves the allocated size of the buffer. + + + + + Represents a description of a media format. + http://msdn.microsoft.com/en-us/library/windows/desktop/ms704850%28v=vs.85%29.aspx + + + + + Retrieves the value associated with a key. + + + + + Retrieves the data type of the value associated with a key. + + + + + Queries whether a stored attribute value equals a specified PROPVARIANT. + + + + + Compares the attributes on this object with the attributes on another object. + + + + + Retrieves a UINT32 value associated with a key. + + + + + Retrieves a UINT64 value associated with a key. + + + + + Retrieves a double value associated with a key. + + + + + Retrieves a GUID value associated with a key. + + + + + Retrieves the length of a string value associated with a key. + + + + + Retrieves a wide-character string associated with a key. + + + + + Retrieves a wide-character string associated with a key. This method allocates the memory for the string. + + + + + Retrieves the length of a byte array associated with a key. + + + + + Retrieves a byte array associated with a key. + + + + + Retrieves a byte array associated with a key. This method allocates the memory for the array. + + + + + Retrieves an interface pointer associated with a key. + + + + + Associates an attribute value with a key. + + + + + Removes a key/value pair from the object's attribute list. + + + + + Removes all key/value pairs from the object's attribute list. + + + + + Associates a UINT32 value with a key. + + + + + Associates a UINT64 value with a key. + + + + + Associates a double value with a key. + + + + + Associates a GUID value with a key. + + + + + Associates a wide-character string with a key. + + + + + Associates a byte array with a key. + + + + + Associates an IUnknown pointer with a key. + + + + + Locks the attribute store so that no other thread can access it. + + + + + Unlocks the attribute store. + + + + + Retrieves the number of attributes that are set on this object. + + + + + Retrieves an attribute at the specified index. + + + + + Copies all of the attributes from this object into another attribute store. + + + + + Retrieves the major type of the format. + + + + + Queries whether the media type is a compressed format. + + + + + Compares two media types and determines whether they are identical. + + + + + Retrieves an alternative representation of the media type. + + + + + Frees memory that was allocated by the GetRepresentation method. + + + + + http://msdn.microsoft.com/en-gb/library/windows/desktop/ms702192%28v=vs.85%29.aspx + + + + + Retrieves the value associated with a key. + + + + + Retrieves the data type of the value associated with a key. + + + + + Queries whether a stored attribute value equals a specified PROPVARIANT. + + + + + Compares the attributes on this object with the attributes on another object. + + + + + Retrieves a UINT32 value associated with a key. + + + + + Retrieves a UINT64 value associated with a key. + + + + + Retrieves a double value associated with a key. + + + + + Retrieves a GUID value associated with a key. + + + + + Retrieves the length of a string value associated with a key. + + + + + Retrieves a wide-character string associated with a key. + + + + + Retrieves a wide-character string associated with a key. This method allocates the memory for the string. + + + + + Retrieves the length of a byte array associated with a key. + + + + + Retrieves a byte array associated with a key. + + + + + Retrieves a byte array associated with a key. This method allocates the memory for the array. + + + + + Retrieves an interface pointer associated with a key. + + + + + Associates an attribute value with a key. + + + + + Removes a key/value pair from the object's attribute list. + + + + + Removes all key/value pairs from the object's attribute list. + + + + + Associates a UINT32 value with a key. + + + + + Associates a UINT64 value with a key. + + + + + Associates a double value with a key. + + + + + Associates a GUID value with a key. + + + + + Associates a wide-character string with a key. + + + + + Associates a byte array with a key. + + + + + Associates an IUnknown pointer with a key. + + + + + Locks the attribute store so that no other thread can access it. + + + + + Unlocks the attribute store. + + + + + Retrieves the number of attributes that are set on this object. + + + + + Retrieves an attribute at the specified index. + + + + + Copies all of the attributes from this object into another attribute store. + + + + + Retrieves flags associated with the sample. + + + + + Sets flags associated with the sample. + + + + + Retrieves the presentation time of the sample. + + + + + Sets the presentation time of the sample. + + + + + Retrieves the duration of the sample. + + + + + Sets the duration of the sample. + + + + + Retrieves the number of buffers in the sample. + + + + + Retrieves a buffer from the sample. + + + + + Converts a sample with multiple buffers into a sample with a single buffer. + + + + + Adds a buffer to the end of the list of buffers in the sample. + + + + + Removes a buffer at a specified index from the sample. + + + + + Removes all buffers from the sample. + + + + + Retrieves the total length of the valid data in all of the buffers in the sample. + + + + + Copies the sample data to a buffer. + + + + + IMFSourceReader interface + http://msdn.microsoft.com/en-us/library/windows/desktop/dd374655%28v=vs.85%29.aspx + + + + + Queries whether a stream is selected. + + + + + Selects or deselects one or more streams. + + + + + Gets a format that is supported natively by the media source. + + + + + Gets the current media type for a stream. + + + + + Sets the media type for a stream. + + + + + Seeks to a new position in the media source. + + + + + Reads the next sample from the media source. + + + + + Flushes one or more streams. + + + + + Queries the underlying media source or decoder for an interface. + + + + + Gets an attribute from the underlying media source. + + + + + Contains flags that indicate the status of the IMFSourceReader::ReadSample method + http://msdn.microsoft.com/en-us/library/windows/desktop/dd375773(v=vs.85).aspx + + + + + No Error + + + + + An error occurred. If you receive this flag, do not make any further calls to IMFSourceReader methods. + + + + + The source reader reached the end of the stream. + + + + + One or more new streams were created + + + + + The native format has changed for one or more streams. The native format is the format delivered by the media source before any decoders are inserted. + + + + + The current media has type changed for one or more streams. To get the current media type, call the IMFSourceReader::GetCurrentMediaType method. + + + + + There is a gap in the stream. This flag corresponds to an MEStreamTick event from the media source. + + + + + All transforms inserted by the application have been removed for a particular stream. + + + + + Media Foundation Transform Categories + + + + + MFT_CATEGORY_VIDEO_DECODER + + + + + MFT_CATEGORY_VIDEO_ENCODER + + + + + MFT_CATEGORY_VIDEO_EFFECT + + + + + MFT_CATEGORY_MULTIPLEXER + + + + + MFT_CATEGORY_DEMULTIPLEXER + + + + + MFT_CATEGORY_AUDIO_DECODER + + + + + MFT_CATEGORY_AUDIO_ENCODER + + + + + MFT_CATEGORY_AUDIO_EFFECT + + + + + MFT_CATEGORY_VIDEO_PROCESSOR + + + + + MFT_CATEGORY_OTHER + + + + + Contains information about an input stream on a Media Foundation transform (MFT) + + + + + Maximum amount of time between an input sample and the corresponding output sample, in 100-nanosecond units. + + + + + Bitwise OR of zero or more flags from the _MFT_INPUT_STREAM_INFO_FLAGS enumeration. + + + + + The minimum size of each input buffer, in bytes. + + + + + Maximum amount of input data, in bytes, that the MFT holds to perform lookahead. + + + + + The memory alignment required for input buffers. If the MFT does not require a specific alignment, the value is zero. + + + + + Contains information about an output buffer for a Media Foundation transform. + + + + + Output stream identifier. + + + + + Pointer to the IMFSample interface. + + + + + Before calling ProcessOutput, set this member to zero. + + + + + Before calling ProcessOutput, set this member to NULL. + + + + + Contains information about an output stream on a Media Foundation transform (MFT). + + + + + Bitwise OR of zero or more flags from the _MFT_OUTPUT_STREAM_INFO_FLAGS enumeration. + + + + + Minimum size of each output buffer, in bytes. + + + + + The memory alignment required for output buffers. + + + + + Defines messages for a Media Foundation transform (MFT). + + + + + Requests the MFT to flush all stored data. + + + + + Requests the MFT to drain any stored data. + + + + + Sets or clears the Direct3D Device Manager for DirectX Video Accereration (DXVA). + + + + + Drop samples - requires Windows 7 + + + + + Command Tick - requires Windows 8 + + + + + Notifies the MFT that streaming is about to begin. + + + + + Notifies the MFT that streaming is about to end. + + + + + Notifies the MFT that an input stream has ended. + + + + + Notifies the MFT that the first sample is about to be processed. + + + + + Marks a point in the stream. This message applies only to asynchronous MFTs. Requires Windows 7 + + + + + Contains media type information for registering a Media Foundation transform (MFT). + + + + + The major media type. + + + + + The Media Subtype + + + + + Contains statistics about the performance of the sink writer. + + + + + The size of the structure, in bytes. + + + + + The time stamp of the most recent sample given to the sink writer. + + + + + The time stamp of the most recent sample to be encoded. + + + + + The time stamp of the most recent sample given to the media sink. + + + + + The time stamp of the most recent stream tick. + + + + + The system time of the most recent sample request from the media sink. + + + + + The number of samples received. + + + + + The number of samples encoded. + + + + + The number of samples given to the media sink. + + + + + The number of stream ticks received. + + + + + The amount of data, in bytes, currently waiting to be processed. + + + + + The total amount of data, in bytes, that has been sent to the media sink. + + + + + The number of pending sample requests. + + + + + The average rate, in media samples per 100-nanoseconds, at which the application sent samples to the sink writer. + + + + + The average rate, in media samples per 100-nanoseconds, at which the sink writer sent samples to the encoder + + + + + The average rate, in media samples per 100-nanoseconds, at which the sink writer sent samples to the media sink. + + + + + Contains flags for registering and enumeration Media Foundation transforms (MFTs). + + + + + None + + + + + The MFT performs synchronous data processing in software. + + + + + The MFT performs asynchronous data processing in software. + + + + + The MFT performs hardware-based data processing, using either the AVStream driver or a GPU-based proxy MFT. + + + + + The MFT that must be unlocked by the application before use. + + + + + For enumeration, include MFTs that were registered in the caller's process. + + + + + The MFT is optimized for transcoding rather than playback. + + + + + For enumeration, sort and filter the results. + + + + + Bitwise OR of all the flags, excluding MFT_ENUM_FLAG_SORTANDFILTER. + + + + + Indicates the status of an input stream on a Media Foundation transform (MFT). + + + + + None + + + + + The input stream can receive more data at this time. + + + + + Describes an input stream on a Media Foundation transform (MFT). + + + + + No flags set + + + + + Each media sample (IMFSample interface) of input data must contain complete, unbroken units of data. + + + + + Each media sample that the client provides as input must contain exactly one unit of data, as defined for the MFT_INPUT_STREAM_WHOLE_SAMPLES flag. + + + + + All input samples must be the same size. + + + + + MTF Input Stream Holds buffers + + + + + The MFT does not hold input samples after the IMFTransform::ProcessInput method returns. + + + + + This input stream can be removed by calling IMFTransform::DeleteInputStream. + + + + + This input stream is optional. + + + + + The MFT can perform in-place processing. + + + + + Defines flags for the IMFTransform::ProcessOutput method. + + + + + None + + + + + The MFT can still generate output from this stream without receiving any more input. + + + + + The format has changed on this output stream, or there is a new preferred format for this stream. + + + + + The MFT has removed this output stream. + + + + + There is no sample ready for this stream. + + + + + Indicates whether a Media Foundation transform (MFT) can produce output data. + + + + + None + + + + + There is a sample available for at least one output stream. + + + + + Describes an output stream on a Media Foundation transform (MFT). + + + + + No flags set + + + + + Each media sample (IMFSample interface) of output data from the MFT contains complete, unbroken units of data. + + + + + Each output sample contains exactly one unit of data, as defined for the MFT_OUTPUT_STREAM_WHOLE_SAMPLES flag. + + + + + All output samples are the same size. + + + + + The MFT can discard the output data from this output stream, if requested by the client. + + + + + This output stream is optional. + + + + + The MFT provides the output samples for this stream, either by allocating them internally or by operating directly on the input samples. + + + + + The MFT can either provide output samples for this stream or it can use samples that the client allocates. + + + + + The MFT does not require the client to process the output for this stream. + + + + + The MFT might remove this output stream during streaming. + + + + + Defines flags for processing output samples in a Media Foundation transform (MFT). + + + + + None + + + + + Do not produce output for streams in which the pSample member of the MFT_OUTPUT_DATA_BUFFER structure is NULL. + + + + + Regenerates the last output sample. + + + + + Process Output Status flags + + + + + None + + + + + The Media Foundation transform (MFT) has created one or more new output streams. + + + + + Defines flags for the setting or testing the media type on a Media Foundation transform (MFT). + + + + + None + + + + + Test the proposed media type, but do not set it. + + + + + Media Type helper class, simplifying working with IMFMediaType + (will probably change in the future, to inherit from an attributes class) + Currently does not release the COM object, so you must do that yourself + + + + + Wraps an existing IMFMediaType object + + The IMFMediaType object + + + + Creates and wraps a new IMFMediaType object + + + + + Creates and wraps a new IMFMediaType object based on a WaveFormat + + WaveFormat + + + + Tries to get a UINT32 value, returning a default value if it doesn't exist + + Attribute key + Default value + Value or default if key doesn't exist + + + + The Sample Rate (valid for audio media types) + + + + + The number of Channels (valid for audio media types) + + + + + The number of bits per sample (n.b. not always valid for compressed audio types) + + + + + The average bytes per second (valid for audio media types) + + + + + The Media Subtype. For audio, is a value from the AudioSubtypes class + + + + + The Major type, e.g. audio or video (from the MediaTypes class) + + + + + Access to the actual IMFMediaType object + Use to pass to MF APIs or Marshal.ReleaseComObject when you are finished with it + + + + + An abstract base class for simplifying working with Media Foundation Transforms + You need to override the method that actually creates and configures the transform + + + + + The Source Provider + + + + + The Output WaveFormat + + + + + Constructs a new MediaFoundationTransform wrapper + Will read one second at a time + + The source provider for input data to the transform + The desired output format + + + + To be implemented by overriding classes. Create the transform object, set up its input and output types, + and configure any custom properties in here + + An object implementing IMFTrasform + + + + Disposes this MediaFoundation transform + + + + + Disposes this Media Foundation Transform + + + + + Destructor + + + + + The output WaveFormat of this Media Foundation Transform + + + + + Reads data out of the source, passing it through the transform + + Output buffer + Offset within buffer to write to + Desired byte count + Number of bytes read + + + + Attempts to read from the transform + Some useful info here: + http://msdn.microsoft.com/en-gb/library/windows/desktop/aa965264%28v=vs.85%29.aspx#process_data + + + + + + Indicate that the source has been repositioned and completely drain out the transforms buffers + + + + + Represents a MIDI meta event with raw data + + + + + Raw data contained in the meta event + + + + + Creates a meta event with raw data + + + + + Creates a deep clone of this MIDI event. + + + + + Describes this meta event + + + + + + + + + + MIDI In Message Information + + + + + Create a new MIDI In Message EventArgs + + + + + + + The Raw message received from the MIDI In API + + + + + The raw message interpreted as a MidiEvent + + + + + The timestamp in milliseconds for this message + + + + + Represents a MIDI Channel AfterTouch Event. + + + + + Creates a new ChannelAfterTouchEvent from raw MIDI data + + A binary reader + + + + Creates a new Channel After-Touch Event + + Absolute time + Channel + After-touch pressure + + + + Calls base class export first, then exports the data + specific to this event + MidiEvent.Export + + + + + The aftertouch pressure value + + + + + Represents a MIDI control change event + + + + + Reads a control change event from a MIDI stream + + Binary reader on the MIDI stream + + + + Creates a control change event + + Time + MIDI Channel Number + The MIDI Controller + Controller value + + + + Describes this control change event + + A string describing this event + + + + + + + + + Calls base class export first, then exports the data + specific to this event + MidiEvent.Export + + + + + The controller number + + + + + The controller value + + + + + Represents a MIDI key signature event event + + + + + Reads a new track sequence number event from a MIDI stream + + The MIDI stream + the data length + + + + Creates a new Key signature event with the specified data + + + + + Creates a deep clone of this MIDI event. + + + + + Number of sharps or flats + + + + + Major or Minor key + + + + + Describes this event + + String describing the event + + + + Calls base class export first, then exports the data + specific to this event + MidiEvent.Export + + + + + Represents a MIDI meta event + + + + + Gets the type of this meta event + + + + + Empty constructor + + + + + Custom constructor for use by derived types, who will manage the data themselves + + Meta event type + Meta data length + Absolute time + + + + Creates a deep clone of this MIDI event. + + + + + Reads a meta-event from a stream + + A binary reader based on the stream of MIDI data + A new MetaEvent object + + + + Describes this meta event + + + + + + + + + + MIDI MetaEvent Type + + + + Track sequence number + + + Text event + + + Copyright + + + Sequence track name + + + Track instrument name + + + Lyric + + + Marker + + + Cue point + + + Program (patch) name + + + Device (port) name + + + MIDI Channel (not official?) + + + MIDI Port (not official?) + + + End track + + + Set tempo + + + SMPTE offset + + + Time signature + + + Key signature + + + Sequencer specific + + + + MIDI command codes + + + + Note Off + + + Note On + + + Key After-touch + + + Control change + + + Patch change + + + Channel after-touch + + + Pitch wheel change + + + Sysex message + + + Eox (comes at end of a sysex message) + + + Timing clock (used when synchronization is required) + + + Start sequence + + + Continue sequence + + + Stop sequence + + + Auto-Sensing + + + Meta-event + + + + MidiController enumeration + http://www.midi.org/techspecs/midimessages.php#3 + + + + Bank Select (MSB) + + + Modulation (MSB) + + + Breath Controller + + + Foot controller (MSB) + + + Main volume + + + Pan + + + Expression + + + Bank Select LSB + + + Sustain + + + Portamento On/Off + + + Sostenuto On/Off + + + Soft Pedal On/Off + + + Legato Footswitch + + + Reset all controllers + + + All notes off + + + + Represents an individual MIDI event + + + + The MIDI command code + + + + Creates a MidiEvent from a raw message received using + the MME MIDI In APIs + + The short MIDI message + A new MIDI Event + + + + Constructs a MidiEvent from a BinaryStream + + The binary stream of MIDI data + The previous MIDI event (pass null for first event) + A new MidiEvent + + + + Converts this MIDI event to a short message (32 bit integer) that + can be sent by the Windows MIDI out short message APIs + Cannot be implemented for all MIDI messages + + A short message + + + + Default constructor + + + + + Creates a MIDI event with specified parameters + + Absolute time of this event + MIDI channel number + MIDI command code + + + + Creates a deep clone of this MIDI event. + + + + + The MIDI Channel Number for this event (1-16) + + + + + The Delta time for this event + + + + + The absolute time for this event + + + + + The command code for this event + + + + + Whether this is a note off event + + + + + Whether this is a note on event + + + + + Determines if this is an end track event + + + + + Displays a summary of the MIDI event + + A string containing a brief description of this MIDI event + + + + Utility function that can read a variable length integer from a binary stream + + The binary stream + The integer read + + + + Writes a variable length integer to a binary stream + + Binary stream + The value to write + + + + Exports this MIDI event's data + Overriden in derived classes, but they should call this version + + Absolute time used to calculate delta. + Is updated ready for the next delta calculation + Stream to write to + + + + A helper class to manage collection of MIDI events + It has the ability to organise them in tracks + + + + + Creates a new Midi Event collection + + Initial file type + Delta Ticks Per Quarter Note + + + + The number of tracks + + + + + The absolute time that should be considered as time zero + Not directly used here, but useful for timeshifting applications + + + + + The number of ticks per quarter note + + + + + Gets events on a specified track + + Track number + The list of events + + + + Gets events on a specific track + + Track number + The list of events + + + + Adds a new track + + The new track event list + + + + Adds a new track + + Initial events to add to the new track + The new track event list + + + + Removes a track + + Track number to remove + + + + Clears all events + + + + + The MIDI file type + + + + + Adds an event to the appropriate track depending on file type + + The event to be added + The original (or desired) track number + When adding events in type 0 mode, the originalTrack parameter + is ignored. If in type 1 mode, it will use the original track number to + store the new events. If the original track was 0 and this is a channel based + event, it will create new tracks if necessary and put it on the track corresponding + to its channel number + + + + Sorts, removes empty tracks and adds end track markers + + + + + Gets an enumerator for the lists of track events + + + + + Gets an enumerator for the lists of track events + + + + + Utility class for comparing MidiEvent objects + + + + + Compares two MidiEvents + Sorts by time, with EndTrack always sorted to the end + + + + + Class able to read a MIDI file + + + + + Opens a MIDI file for reading + + Name of MIDI file + + + + MIDI File format + + + + + Opens a MIDI file for reading + + Name of MIDI file + If true will error on non-paired note events + + + + The collection of events in this MIDI file + + + + + Number of tracks in this MIDI file + + + + + Delta Ticks Per Quarter Note + + + + + Describes the MIDI file + + A string describing the MIDI file and its events + + + + Exports a MIDI file + + Filename to export to + Events to export + + + + Represents a MIDI in device + + + + + Called when a MIDI message is received + + + + + An invalid MIDI message + + + + + Gets the number of MIDI input devices available in the system + + + + + Opens a specified MIDI in device + + The device number + + + + Closes this MIDI in device + + + + + Closes this MIDI in device + + + + + Start the MIDI in device + + + + + Stop the MIDI in device + + + + + Reset the MIDI in device + + + + + Gets the MIDI in device info + + + + + Closes the MIDI out device + + True if called from Dispose + + + + Cleanup + + + + + MIDI In Device Capabilities + + + + + wMid + + + + + wPid + + + + + vDriverVersion + + + + + Product Name + + + + + Support - Reserved + + + + + Gets the manufacturer of this device + + + + + Gets the product identifier (manufacturer specific) + + + + + Gets the product name + + + + + MIM_OPEN + + + + + MIM_CLOSE + + + + + MIM_DATA + + + + + MIM_LONGDATA + + + + + MIM_ERROR + + + + + MIM_LONGERROR + + + + + MIM_MOREDATA + + + + + MOM_OPEN + + + + + MOM_CLOSE + + + + + MOM_DONE + + + + + Represents a MIDI message + + + + + Creates a new MIDI message + + Status + Data parameter 1 + Data parameter 2 + + + + Creates a new MIDI message from a raw message + + A packed MIDI message from an MMIO function + + + + Creates a Note On message + + Note number (0 to 127) + Volume (0 to 127) + MIDI channel (1 to 16) + A new MidiMessage object + + + + Creates a Note Off message + + Note number + Volume + MIDI channel (1-16) + A new MidiMessage object + + + + Creates a patch change message + + The patch number + The MIDI channel number (1-16) + A new MidiMessageObject + + + + Creates a Control Change message + + The controller number to change + The value to set the controller to + The MIDI channel number (1-16) + A new MidiMessageObject + + + + Returns the raw MIDI message data + + + + + Represents a MIDI out device + + + + + Gets the number of MIDI devices available in the system + + + + + Gets the MIDI Out device info + + + + + Opens a specified MIDI out device + + The device number + + + + Closes this MIDI out device + + + + + Closes this MIDI out device + + + + + Gets or sets the volume for this MIDI out device + + + + + Resets the MIDI out device + + + + + Sends a MIDI out message + + Message + Parameter 1 + Parameter 2 + + + + Sends a MIDI message to the MIDI out device + + The message to send + + + + Closes the MIDI out device + + True if called from Dispose + + + + Send a long message, for example sysex. + + The bytes to send. + + + + Cleanup + + + + + class representing the capabilities of a MIDI out device + MIDIOUTCAPS: http://msdn.microsoft.com/en-us/library/dd798467%28VS.85%29.aspx + + + + + MIDICAPS_VOLUME + + + + + separate left-right volume control + MIDICAPS_LRVOLUME + + + + + MIDICAPS_CACHE + + + + + MIDICAPS_STREAM + driver supports midiStreamOut directly + + + + + Gets the manufacturer of this device + + + + + Gets the product identifier (manufacturer specific) + + + + + Gets the product name + + + + + Returns the number of supported voices + + + + + Gets the polyphony of the device + + + + + Returns true if the device supports all channels + + + + + Queries whether a particular channel is supported + + Channel number to test + True if the channel is supported + + + + Returns true if the device supports patch caching + + + + + Returns true if the device supports separate left and right volume + + + + + Returns true if the device supports MIDI stream out + + + + + Returns true if the device supports volume control + + + + + Returns the type of technology used by this MIDI out device + + + + + Represents the different types of technology used by a MIDI out device + + from mmsystem.h + + + The device is a MIDI port + + + The device is a MIDI synth + + + The device is a square wave synth + + + The device is an FM synth + + + The device is a MIDI mapper + + + The device is a WaveTable synth + + + The device is a software synth + + + + Represents a note MIDI event + + + + + Reads a NoteEvent from a stream of MIDI data + + Binary Reader for the stream + + + + Creates a MIDI Note Event with specified parameters + + Absolute time of this event + MIDI channel number + MIDI command code + MIDI Note Number + MIDI Note Velocity + + + + + + + + + The MIDI note number + + + + + The note velocity + + + + + The note name + + + + + Describes the Note Event + + Note event as a string + + + + + + + + + Represents a MIDI note on event + + + + + Reads a new Note On event from a stream of MIDI data + + Binary reader on the MIDI data stream + + + + Creates a NoteOn event with specified parameters + + Absolute time of this event + MIDI channel number + MIDI note number + MIDI note velocity + MIDI note duration + + + + Creates a deep clone of this MIDI event. + + + + + The associated Note off event + + + + + Get or set the Note Number, updating the off event at the same time + + + + + Get or set the channel, updating the off event at the same time + + + + + The duration of this note + + + There must be a note off event + + + + + Calls base class export first, then exports the data + specific to this event + MidiEvent.Export + + + + + Represents a MIDI patch change event + + + + + Gets the default MIDI instrument names + + + + + Reads a new patch change event from a MIDI stream + + Binary reader for the MIDI stream + + + + Creates a new patch change event + + Time of the event + Channel number + Patch number + + + + The Patch Number + + + + + Describes this patch change event + + String describing the patch change event + + + + Gets as a short message for sending with the midiOutShortMsg API + + short message + + + + Calls base class export first, then exports the data + specific to this event + MidiEvent.Export + + + + + Represents a MIDI pitch wheel change event + + + + + Reads a pitch wheel change event from a MIDI stream + + The MIDI stream to read from + + + + Creates a new pitch wheel change event + + Absolute event time + Channel + Pitch wheel value + + + + Describes this pitch wheel change event + + String describing this pitch wheel change event + + + + Pitch Wheel Value 0 is minimum, 0x2000 (8192) is default, 0x3FFF (16383) is maximum + + + + + Gets a short message + + Integer to sent as short message + + + + Calls base class export first, then exports the data + specific to this event + MidiEvent.Export + + + + + Represents a Sequencer Specific event + + + + + Reads a new sequencer specific event from a MIDI stream + + The MIDI stream + The data length + + + + Creates a new Sequencer Specific event + + The sequencer specific data + Absolute time of this event + + + + Creates a deep clone of this MIDI event. + + + + + The contents of this sequencer specific + + + + + Describes this MIDI text event + + A string describing this event + + + + Calls base class export first, then exports the data + specific to this event + MidiEvent.Export + + + + + Creates a new time signature event + + + + + Reads a new time signature event from a MIDI stream + + The MIDI stream + The data length + + + + Creates a deep clone of this MIDI event. + + + + + Hours + + + + + Minutes + + + + + Seconds + + + + + Frames + + + + + SubFrames + + + + + Describes this time signature event + + A string describing this event + + + + Calls base class export first, then exports the data + specific to this event + MidiEvent.Export + + + + + Represents a MIDI sysex message + + + + + Reads a sysex message from a MIDI stream + + Stream of MIDI data + a new sysex message + + + + Creates a deep clone of this MIDI event. + + + + + Describes this sysex message + + A string describing the sysex message + + + + Calls base class export first, then exports the data + specific to this event + MidiEvent.Export + + + + + Represents a MIDI tempo event + + + + + Reads a new tempo event from a MIDI stream + + The MIDI stream + the data length + + + + Creates a new tempo event with specified settings + + Microseconds per quarter note + Absolute time + + + + Creates a deep clone of this MIDI event. + + + + + Describes this tempo event + + String describing the tempo event + + + + Microseconds per quarter note + + + + + Tempo + + + + + Calls base class export first, then exports the data + specific to this event + MidiEvent.Export + + + + + Represents a MIDI text event + + + + + Reads a new text event from a MIDI stream + + The MIDI stream + The data length + + + + Creates a new TextEvent + + The text in this type + MetaEvent type (must be one that is + associated with text data) + Absolute time of this event + + + + Creates a deep clone of this MIDI event. + + + + + The contents of this text event + + + + + Describes this MIDI text event + + A string describing this event + + + + Calls base class export first, then exports the data + specific to this event + MidiEvent.Export + + + + + Represents a MIDI time signature event + + + + + Reads a new time signature event from a MIDI stream + + The MIDI stream + The data length + + + + Creates a new TimeSignatureEvent + + Time at which to create this event + Numerator + Denominator + Ticks in Metronome Click + No of 32nd Notes in Quarter Click + + + + Creates a deep clone of this MIDI event. + + + + + Numerator (number of beats in a bar) + + + + + Denominator (Beat unit), + 1 means 2, 2 means 4 (crochet), 3 means 8 (quaver), 4 means 16 and 5 means 32 + + + + + Ticks in a metronome click + + + + + Number of 32nd notes in a quarter note + + + + + The time signature + + + + + Describes this time signature event + + A string describing this event + + + + Calls base class export first, then exports the data + specific to this event + MidiEvent.Export + + + + + Represents a MIDI track sequence number event event + + + + + Creates a new track sequence number event + + + + + Reads a new track sequence number event from a MIDI stream + + The MIDI stream + the data length + + + + Creates a deep clone of this MIDI event. + + + + + Describes this event + + String describing the event + + + + Calls base class export first, then exports the data + specific to this event + MidiEvent.Export + + + + + Chunk Identifier helpers + + + + + Chunk identifier to Int32 (replaces mmioStringToFOURCC) + + four character chunk identifier + Chunk identifier as int 32 + + + + Allows us to add descriptions to interop members + + + + + The description + + + + + Field description + + + + + String representation + + + + + + these will become extension methods once we move to .NET 3.5 + + + + + Checks if the buffer passed in is entirely full of nulls + + + + + Converts to a string containing the buffer described in hex + + + + + Decodes the buffer using the specified encoding, stopping at the first null + + + + + Concatenates the given arrays into a single array. + + The arrays to concatenate + The concatenated resulting array. + + + + Helper to get descriptions + + + + + Describes the Guid by looking for a FieldDescription attribute on the specified class + + + + + Support for Marshal Methods in both UWP and .NET 3.5 + + + + + SizeOf a structure + + + + + Offset of a field in a structure + + + + + Pointer to Structure + + + + + WavePosition extension methods + + + + + Get Position as timespan + + + + + Methods for converting between IEEE 80-bit extended double precision + and standard C# double precision. + + + + + Converts a C# double precision number to an 80-bit + IEEE extended double precision number (occupying 10 bytes). + + The double precision number to convert to IEEE extended. + An array of 10 bytes containing the IEEE extended number. + + + + Converts an IEEE 80-bit extended precision number to a + C# double precision number. + + The 80-bit IEEE extended number (as an array of 10 bytes). + A C# double precision number that is a close representation of the IEEE extended number. + + + + General purpose native methods for internal NAudio use + + + + + Helper methods for working with audio buffers + + + + + Ensures the buffer is big enough + + + + + + + + Ensures the buffer is big enough + + + + + + + + An encoding for use with file types that have one byte per character + + + + + The one and only instance of this class + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + A very basic circular buffer implementation + + + + + Create a new circular buffer + + Max buffer size in bytes + + + + Write data to the buffer + + Data to write + Offset into data + Number of bytes to write + number of bytes written + + + + Read from the buffer + + Buffer to read into + Offset into read buffer + Bytes to read + Number of bytes actually read + + + + Maximum length of this circular buffer + + + + + Number of bytes currently stored in the circular buffer + + + + + Resets the buffer + + + + + Advances the buffer, discarding bytes + + Bytes to advance + + + + A util class for conversions + + + + + linear to dB conversion + + linear value + decibel value + + + + dB to linear conversion + + decibel value + linear value + + + + HResult + + + + + S_OK + + + + + S_FALSE + + + + + E_INVALIDARG (from winerror.h) + + + + + MAKE_HRESULT macro + + + + + Helper to deal with the fact that in Win Store apps, + the HResult property name has changed + + COM Exception + The HResult + + + + Pass-through stream that ignores Dispose + Useful for dealing with MemoryStreams that you want to re-use + + + + + The source stream all other methods fall through to + + + + + If true the Dispose will be ignored, if false, will pass through to the SourceStream + Set to true by default + + + + + Creates a new IgnoreDisposeStream + + The source stream + + + + Can Read + + + + + Can Seek + + + + + Can write to the underlying stream + + + + + Flushes the underlying stream + + + + + Gets the length of the underlying stream + + + + + Gets or sets the position of the underlying stream + + + + + Reads from the underlying stream + + + + + Seeks on the underlying stream + + + + + Sets the length of the underlying stream + + + + + Writes to the underlying stream + + + + + Dispose - by default (IgnoreDispose = true) will do nothing, + leaving the underlying stream undisposed + + + + + In-place and stable implementation of MergeSort + + + + + MergeSort a list of comparable items + + + + + MergeSort a list + + + + + A thread-safe Progress Log Control + + + + + Creates a new progress log control + + + + + The contents of the log as text + + + + + Log a message + + + + + Clear the log + + + + + Required designer variable. + + + + + Clean up any resources being used. + + true if managed resources should be disposed; otherwise, false. + + + + Required method for Designer support - do not modify + the contents of this method with the code editor. + + + + + ASIO 64 bit value + Unfortunately the ASIO API was implemented it before compiler supported consistently 64 bit + integer types. By using the structure the data layout on a little-endian system like the + Intel x86 architecture will result in a "non native" storage of the 64 bit data. The most + significant 32 bit are stored first in memory, the least significant bits are stored in the + higher memory space. However each 32 bit is stored in the native little-endian fashion + + + + + most significant bits (Bits 32..63) + + + + + least significant bits (Bits 0..31) + + + + + ASIO Callbacks + + + + + ASIO Buffer Switch Callback + + + + + ASIO Sample Rate Did Change Callback + + + + + ASIO Message Callback + + + + + ASIO Buffer Switch Time Info Callback + + + + + Buffer switch callback + void (*bufferSwitch) (long doubleBufferIndex, AsioBool directProcess); + + + + + Sample Rate Changed callback + void (*sampleRateDidChange) (AsioSampleRate sRate); + + + + + ASIO Message callback + long (*asioMessage) (long selector, long value, void* message, double* opt); + + + + + ASIO Buffer Switch Time Info Callback + AsioTime* (*bufferSwitchTimeInfo) (AsioTime* params, long doubleBufferIndex, AsioBool directProcess); + + + + + ASIO Channel Info + + + + + on input, channel index + + + + + Is Input + + + + + Is Active + + + + + Channel Info + + + + + ASIO Sample Type + + + + + Name + + + + + ASIODriverCapability holds all the information from the AsioDriver. + Use ASIODriverExt to get the Capabilities + + + + + Drive Name + + + + + Number of Input Channels + + + + + Number of Output Channels + + + + + Input Latency + + + + + Output Latency + + + + + Buffer Minimum Size + + + + + Buffer Maximum Size + + + + + Buffer Preferred Size + + + + + Buffer Granularity + + + + + Sample Rate + + + + + Input Channel Info + + + + + Output Channel Info + + + + + ASIO Error Codes + + + + + This value will be returned whenever the call succeeded + + + + + unique success return value for ASIOFuture calls + + + + + hardware input or output is not present or available + + + + + hardware is malfunctioning (can be returned by any ASIO function) + + + + + input parameter invalid + + + + + hardware is in a bad mode or used in a bad mode + + + + + hardware is not running when sample position is inquired + + + + + sample clock or rate cannot be determined or is not present + + + + + not enough memory for completing the request + + + + + ASIO Message Selector + + + + + selector in <value>, returns 1L if supported, + + + + + returns engine (host) asio implementation version, + + + + + request driver reset. if accepted, this + + + + + not yet supported, will currently always return 0L. + + + + + the driver went out of sync, such that + + + + + the drivers latencies have changed. The engine + + + + + if host returns true here, it will expect the + + + + + supports timecode + + + + + unused - value: number of commands, message points to mmc commands + + + + + kAsioSupportsXXX return 1 if host supports this + + + + + unused and undefined + + + + + unused and undefined + + + + + unused and undefined + + + + + unused and undefined + + + + + driver detected an overload + + + + + ASIO Sample Type + + + + + Int 16 MSB + + + + + Int 24 MSB (used for 20 bits as well) + + + + + Int 32 MSB + + + + + IEEE 754 32 bit float + + + + + IEEE 754 64 bit double float + + + + + 32 bit data with 16 bit alignment + + + + + 32 bit data with 18 bit alignment + + + + + 32 bit data with 20 bit alignment + + + + + 32 bit data with 24 bit alignment + + + + + Int 16 LSB + + + + + Int 24 LSB + used for 20 bits as well + + + + + Int 32 LSB + + + + + IEEE 754 32 bit float, as found on Intel x86 architecture + + + + + IEEE 754 64 bit double float, as found on Intel x86 architecture + + + + + 32 bit data with 16 bit alignment + + + + + 32 bit data with 18 bit alignment + + + + + 32 bit data with 20 bit alignment + + + + + 32 bit data with 24 bit alignment + + + + + DSD 1 bit data, 8 samples per byte. First sample in Least significant bit. + + + + + DSD 1 bit data, 8 samples per byte. First sample in Most significant bit. + + + + + DSD 8 bit data, 1 sample per byte. No Endianness required. + + + + + Main AsioDriver Class. To use this class, you need to query first the GetAsioDriverNames() and + then use the GetAsioDriverByName to instantiate the correct AsioDriver. + This is the first AsioDriver binding fully implemented in C#! + + Contributor: Alexandre Mutel - email: alexandre_mutel at yahoo.fr + + + + + Gets the ASIO driver names installed. + + a list of driver names. Use this name to GetAsioDriverByName + + + + Instantiate a AsioDriver given its name. + + The name of the driver + an AsioDriver instance + + + + Instantiate the ASIO driver by GUID. + + The GUID. + an AsioDriver instance + + + + Inits the AsioDriver.. + + The sys handle. + + + + + Gets the name of the driver. + + + + + + Gets the driver version. + + + + + + Gets the error message. + + + + + + Starts this instance. + + + + + Stops this instance. + + + + + Gets the number of channels. + + The num input channels. + The num output channels. + + + + Gets the latencies (n.b. does not throw an exception) + + The input latency. + The output latency. + + + + Gets the size of the buffer. + + Size of the min. + Size of the max. + Size of the preferred. + The granularity. + + + + Determines whether this instance can use the specified sample rate. + + The sample rate. + + true if this instance [can sample rate] the specified sample rate; otherwise, false. + + + + + Gets the sample rate. + + + + + + Sets the sample rate. + + The sample rate. + + + + Gets the clock sources. + + The clocks. + The num sources. + + + + Sets the clock source. + + The reference. + + + + Gets the sample position. + + The sample pos. + The time stamp. + + + + Gets the channel info. + + The channel number. + if set to true [true for input info]. + Channel Info + + + + Creates the buffers. + + The buffer infos. + The num channels. + Size of the buffer. + The callbacks. + + + + Disposes the buffers. + + + + + Controls the panel. + + + + + Futures the specified selector. + + The selector. + The opt. + + + + Notifies OutputReady to the AsioDriver. + + + + + + Releases this instance. + + + + + Handles the exception. Throws an exception based on the error. + + The error to check. + Method name + + + + Inits the vTable method from GUID. This is a tricky part of this class. + + The ASIO GUID. + + + + Internal VTable structure to store all the delegates to the C++ COM method. + + + + + Callback used by the AsioDriverExt to get wave data + + + + + AsioDriverExt is a simplified version of the AsioDriver. It provides an easier + way to access the capabilities of the Driver and implement the callbacks necessary + for feeding the driver. + Implementation inspired from Rob Philpot's with a managed C++ ASIO wrapper BlueWave.Interop.Asio + http://www.codeproject.com/KB/mcpp/Asio.Net.aspx + + Contributor: Alexandre Mutel - email: alexandre_mutel at yahoo.fr + + + + + Initializes a new instance of the class based on an already + instantiated AsioDriver instance. + + A AsioDriver already instantiated. + + + + Allows adjustment of which is the first output channel we write to + + Output Channel offset + Input Channel offset + + + + Gets the driver used. + + The ASIOdriver. + + + + Starts playing the buffers. + + + + + Stops playing the buffers. + + + + + Shows the control panel. + + + + + Releases this instance. + + + + + Determines whether the specified sample rate is supported. + + The sample rate. + + true if [is sample rate supported]; otherwise, false. + + + + + Sets the sample rate. + + The sample rate. + + + + Gets or sets the fill buffer callback. + + The fill buffer callback. + + + + Gets the capabilities of the AsioDriver. + + The capabilities. + + + + Creates the buffers for playing. + + The number of outputs channels. + The number of input channel. + if set to true [use max buffer size] else use Prefered size + + + + Builds the capabilities internally. + + + + + Callback called by the AsioDriver on fill buffer demand. Redirect call to external callback. + + Index of the double buffer. + if set to true [direct process]. + + + + Callback called by the AsioDriver on event "Samples rate changed". + + The sample rate. + + + + Asio message call back. + + The selector. + The value. + The message. + The opt. + + + + + Buffers switch time info call back. + + The asio time param. + Index of the double buffer. + if set to true [direct process]. + + + + + This class stores convertors for different interleaved WaveFormat to ASIOSampleType separate channel + format. + + + + + Selects the sample convertor based on the input WaveFormat and the output ASIOSampleTtype. + + The wave format. + The type. + + + + + Optimized convertor for 2 channels SHORT + + + + + Generic convertor for SHORT + + + + + Optimized convertor for 2 channels FLOAT + + + + + Generic convertor SHORT + + + + + Optimized convertor for 2 channels SHORT + + + + + Generic convertor for SHORT + + + + + Optimized convertor for 2 channels FLOAT + + + + + Generic convertor SHORT + + + + + Generic converter 24 LSB + + + + + Generic convertor for float + + + + + ASIO common Exception. + + + + + Gets the name of the error. + + The error. + the name of the error + + + + Flags for use with acmDriverAdd + + + + + ACM_DRIVERADDF_LOCAL + + + + + ACM_DRIVERADDF_GLOBAL + + + + + ACM_DRIVERADDF_FUNCTION + + + + + ACM_DRIVERADDF_NOTIFYHWND + + + + + Represents an installed ACM Driver + + + + + Helper function to determine whether a particular codec is installed + + The short name of the function + Whether the codec is installed + + + + Attempts to add a new ACM driver from a file + + Full path of the .acm or dll file containing the driver + Handle to the driver + + + + Removes a driver previously added using AddLocalDriver + + Local driver to remove + + + + Show Format Choose Dialog + + Owner window handle, can be null + Window title + Enumeration flags. None to get everything + Enumeration format. Only needed with certain enumeration flags + The selected format + Textual description of the selected format + Textual description of the selected format tag + True if a format was selected + + + + Gets the maximum size needed to store a WaveFormat for ACM interop functions + + + + + Finds a Driver by its short name + + Short Name + The driver, or null if not found + + + + Gets a list of the ACM Drivers installed + + + + + The callback for acmDriverEnum + + + + + Creates a new ACM Driver object + + Driver handle + + + + The short name of this driver + + + + + The full name of this driver + + + + + The driver ID + + + + + ToString + + + + + The list of FormatTags for this ACM Driver + + + + + Gets all the supported formats for a given format tag + + Format tag + Supported formats + + + + Opens this driver + + + + + Closes this driver + + + + + Dispose + + + + + Interop structure for ACM driver details (ACMDRIVERDETAILS) + http://msdn.microsoft.com/en-us/library/dd742889%28VS.85%29.aspx + + + + + DWORD cbStruct + + + + + FOURCC fccType + + + + + FOURCC fccComp + + + + + WORD wMid; + + + + + WORD wPid + + + + + DWORD vdwACM + + + + + DWORD vdwDriver + + + + + DWORD fdwSupport; + + + + + DWORD cFormatTags + + + + + DWORD cFilterTags + + + + + HICON hicon + + + + + TCHAR szShortName[ACMDRIVERDETAILS_SHORTNAME_CHARS]; + + + + + TCHAR szLongName[ACMDRIVERDETAILS_LONGNAME_CHARS]; + + + + + TCHAR szCopyright[ACMDRIVERDETAILS_COPYRIGHT_CHARS]; + + + + + TCHAR szLicensing[ACMDRIVERDETAILS_LICENSING_CHARS]; + + + + + TCHAR szFeatures[ACMDRIVERDETAILS_FEATURES_CHARS]; + + + + + ACMDRIVERDETAILS_SHORTNAME_CHARS + + + + + ACMDRIVERDETAILS_LONGNAME_CHARS + + + + + ACMDRIVERDETAILS_COPYRIGHT_CHARS + + + + + ACMDRIVERDETAILS_LICENSING_CHARS + + + + + ACMDRIVERDETAILS_FEATURES_CHARS + + + + + Flags indicating what support a particular ACM driver has + + + + ACMDRIVERDETAILS_SUPPORTF_CODEC - Codec + + + ACMDRIVERDETAILS_SUPPORTF_CONVERTER - Converter + + + ACMDRIVERDETAILS_SUPPORTF_FILTER - Filter + + + ACMDRIVERDETAILS_SUPPORTF_HARDWARE - Hardware + + + ACMDRIVERDETAILS_SUPPORTF_ASYNC - Async + + + ACMDRIVERDETAILS_SUPPORTF_LOCAL - Local + + + ACMDRIVERDETAILS_SUPPORTF_DISABLED - Disabled + + + + ACM_DRIVERENUMF_NOLOCAL, Only global drivers should be included in the enumeration + + + + + ACM_DRIVERENUMF_DISABLED, Disabled ACM drivers should be included in the enumeration + + + + + ACM Format + + + + + Format Index + + + + + Format Tag + + + + + Support Flags + + + + + WaveFormat + + + + + WaveFormat Size + + + + + Format Description + + + + + ACMFORMATCHOOSE + http://msdn.microsoft.com/en-us/library/dd742911%28VS.85%29.aspx + + + + + DWORD cbStruct; + + + + + DWORD fdwStyle; + + + + + HWND hwndOwner; + + + + + LPWAVEFORMATEX pwfx; + + + + + DWORD cbwfx; + + + + + LPCTSTR pszTitle; + + + + + TCHAR szFormatTag[ACMFORMATTAGDETAILS_FORMATTAG_CHARS]; + + + + + TCHAR szFormat[ACMFORMATDETAILS_FORMAT_CHARS]; + + + + + LPTSTR pszName; + n.b. can be written into + + + + + DWORD cchName + Should be at least 128 unless name is zero + + + + + DWORD fdwEnum; + + + + + LPWAVEFORMATEX pwfxEnum; + + + + + HINSTANCE hInstance; + + + + + LPCTSTR pszTemplateName; + + + + + LPARAM lCustData; + + + + + ACMFORMATCHOOSEHOOKPROC pfnHook; + + + + + None + + + + + ACMFORMATCHOOSE_STYLEF_SHOWHELP + + + + + ACMFORMATCHOOSE_STYLEF_ENABLEHOOK + + + + + ACMFORMATCHOOSE_STYLEF_ENABLETEMPLATE + + + + + ACMFORMATCHOOSE_STYLEF_ENABLETEMPLATEHANDLE + + + + + ACMFORMATCHOOSE_STYLEF_INITTOWFXSTRUCT + + + + + ACMFORMATCHOOSE_STYLEF_CONTEXTHELP + + + + + ACMFORMATDETAILS + http://msdn.microsoft.com/en-us/library/dd742913%28VS.85%29.aspx + + + + + DWORD cbStruct; + + + + + DWORD dwFormatIndex; + + + + + DWORD dwFormatTag; + + + + + DWORD fdwSupport; + + + + + LPWAVEFORMATEX pwfx; + + + + + DWORD cbwfx; + + + + + TCHAR szFormat[ACMFORMATDETAILS_FORMAT_CHARS]; + + + + + ACMFORMATDETAILS_FORMAT_CHARS + + + + + Format Enumeration Flags + + + + + None + + + + + ACM_FORMATENUMF_CONVERT + The WAVEFORMATEX structure pointed to by the pwfx member of the ACMFORMATDETAILS structure is valid. The enumerator will only enumerate destination formats that can be converted from the given pwfx format. + + + + + ACM_FORMATENUMF_HARDWARE + The enumerator should only enumerate formats that are supported as native input or output formats on one or more of the installed waveform-audio devices. This flag provides a way for an application to choose only formats native to an installed waveform-audio device. This flag must be used with one or both of the ACM_FORMATENUMF_INPUT and ACM_FORMATENUMF_OUTPUT flags. Specifying both ACM_FORMATENUMF_INPUT and ACM_FORMATENUMF_OUTPUT will enumerate only formats that can be opened for input or output. This is true regardless of whether this flag is specified. + + + + + ACM_FORMATENUMF_INPUT + Enumerator should enumerate only formats that are supported for input (recording). + + + + + ACM_FORMATENUMF_NCHANNELS + The nChannels member of the WAVEFORMATEX structure pointed to by the pwfx member of the ACMFORMATDETAILS structure is valid. The enumerator will enumerate only a format that conforms to this attribute. + + + + + ACM_FORMATENUMF_NSAMPLESPERSEC + The nSamplesPerSec member of the WAVEFORMATEX structure pointed to by the pwfx member of the ACMFORMATDETAILS structure is valid. The enumerator will enumerate only a format that conforms to this attribute. + + + + + ACM_FORMATENUMF_OUTPUT + Enumerator should enumerate only formats that are supported for output (playback). + + + + + ACM_FORMATENUMF_SUGGEST + The WAVEFORMATEX structure pointed to by the pwfx member of the ACMFORMATDETAILS structure is valid. The enumerator will enumerate all suggested destination formats for the given pwfx format. This mechanism can be used instead of the acmFormatSuggest function to allow an application to choose the best suggested format for conversion. The dwFormatIndex member will always be set to zero on return. + + + + + ACM_FORMATENUMF_WBITSPERSAMPLE + The wBitsPerSample member of the WAVEFORMATEX structure pointed to by the pwfx member of the ACMFORMATDETAILS structure is valid. The enumerator will enumerate only a format that conforms to this attribute. + + + + + ACM_FORMATENUMF_WFORMATTAG + The wFormatTag member of the WAVEFORMATEX structure pointed to by the pwfx member of the ACMFORMATDETAILS structure is valid. The enumerator will enumerate only a format that conforms to this attribute. The dwFormatTag member of the ACMFORMATDETAILS structure must be equal to the wFormatTag member. + + + + + ACM_FORMATSUGGESTF_WFORMATTAG + + + + + ACM_FORMATSUGGESTF_NCHANNELS + + + + + ACM_FORMATSUGGESTF_NSAMPLESPERSEC + + + + + ACM_FORMATSUGGESTF_WBITSPERSAMPLE + + + + + ACM_FORMATSUGGESTF_TYPEMASK + + + + + ACM Format Tag + + + + + Format Tag Index + + + + + Format Tag + + + + + Format Size + + + + + Support Flags + + + + + Standard Formats Count + + + + + Format Description + + + + + DWORD cbStruct; + + + + + DWORD dwFormatTagIndex; + + + + + DWORD dwFormatTag; + + + + + DWORD cbFormatSize; + + + + + DWORD fdwSupport; + + + + + DWORD cStandardFormats; + + + + + TCHAR szFormatTag[ACMFORMATTAGDETAILS_FORMATTAG_CHARS]; + + + + + ACMFORMATTAGDETAILS_FORMATTAG_CHARS + + + + + Interop definitions for Windows ACM (Audio Compression Manager) API + + + + + http://msdn.microsoft.com/en-us/library/dd742910%28VS.85%29.aspx + UINT ACMFORMATCHOOSEHOOKPROC acmFormatChooseHookProc( + HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam + + + + + http://msdn.microsoft.com/en-us/library/dd742916%28VS.85%29.aspx + MMRESULT acmFormatSuggest( + HACMDRIVER had, + LPWAVEFORMATEX pwfxSrc, + LPWAVEFORMATEX pwfxDst, + DWORD cbwfxDst, + DWORD fdwSuggest); + + + + + http://msdn.microsoft.com/en-us/library/dd742928%28VS.85%29.aspx + MMRESULT acmStreamOpen( + LPHACMSTREAM phas, + HACMDRIVER had, + LPWAVEFORMATEX pwfxSrc, + LPWAVEFORMATEX pwfxDst, + LPWAVEFILTER pwfltr, + DWORD_PTR dwCallback, + DWORD_PTR dwInstance, + DWORD fdwOpen + + + + + A version with pointers for troubleshooting + + + + + AcmStream encapsulates an Audio Compression Manager Stream + used to convert audio from one format to another + + + + + Creates a new ACM stream to convert one format to another. Note that + not all conversions can be done in one step + + The source audio format + The destination audio format + + + + Creates a new ACM stream to convert one format to another, using a + specified driver identified and wave filter + + the driver identifier + the source format + the wave filter + + + + Returns the number of output bytes for a given number of input bytes + + Number of input bytes + Number of output bytes + + + + Returns the number of source bytes for a given number of destination bytes + + Number of destination bytes + Number of source bytes + + + + Suggests an appropriate PCM format that the compressed format can be converted + to in one step + + The compressed format + The PCM format + + + + Returns the Source Buffer. Fill this with data prior to calling convert + + + + + Returns the Destination buffer. This will contain the converted data + after a successful call to Convert + + + + + Report that we have repositioned in the source stream + + + + + Converts the contents of the SourceBuffer into the DestinationBuffer + + The number of bytes in the SourceBuffer + that need to be converted + The number of source bytes actually converted + The number of converted bytes in the DestinationBuffer + + + + Converts the contents of the SourceBuffer into the DestinationBuffer + + The number of bytes in the SourceBuffer + that need to be converted + The number of converted bytes in the DestinationBuffer + + + + Frees resources associated with this ACM Stream + + + + + Frees resources associated with this ACM Stream + + + + + Frees resources associated with this ACM Stream + + + + + ACMSTREAMHEADER_STATUSF_DONE + + + + + ACMSTREAMHEADER_STATUSF_PREPARED + + + + + ACMSTREAMHEADER_STATUSF_INQUEUE + + + + + Interop structure for ACM stream headers. + ACMSTREAMHEADER + http://msdn.microsoft.com/en-us/library/dd742926%28VS.85%29.aspx + + + + + ACM_STREAMOPENF_QUERY, ACM will be queried to determine whether it supports the given conversion. A conversion stream will not be opened, and no handle will be returned in the phas parameter. + + + + + ACM_STREAMOPENF_ASYNC, Stream conversion should be performed asynchronously. If this flag is specified, the application can use a callback function to be notified when the conversion stream is opened and closed and after each buffer is converted. In addition to using a callback function, an application can examine the fdwStatus member of the ACMSTREAMHEADER structure for the ACMSTREAMHEADER_STATUSF_DONE flag. + + + + + ACM_STREAMOPENF_NONREALTIME, ACM will not consider time constraints when converting the data. By default, the driver will attempt to convert the data in real time. For some formats, specifying this flag might improve the audio quality or other characteristics. + + + + + CALLBACK_TYPEMASK, callback type mask + + + + + CALLBACK_NULL, no callback + + + + + CALLBACK_WINDOW, dwCallback is a HWND + + + + + CALLBACK_TASK, dwCallback is a HTASK + + + + + CALLBACK_FUNCTION, dwCallback is a FARPROC + + + + + CALLBACK_THREAD, thread ID replaces 16 bit task + + + + + CALLBACK_EVENT, dwCallback is an EVENT Handle + + + + + ACM_STREAMSIZEF_SOURCE + + + + + ACM_STREAMSIZEF_DESTINATION + + + + + Summary description for WaveFilter. + + + + + cbStruct + + + + + dwFilterTag + + + + + fdwFilter + + + + + reserved + + + + + ADSR sample provider allowing you to specify attack, decay, sustain and release values + + + + + Creates a new AdsrSampleProvider with default values + + + + + Attack time in seconds + + + + + Release time in seconds + + + + + Reads audio from this sample provider + + + + + Enters the Release phase + + + + + The output WaveFormat + + + + + Sample Provider to concatenate multiple sample providers together + + + + + Creates a new ConcatenatingSampleProvider + + The source providers to play one after the other. Must all share the same sample rate and channel count + + + + The WaveFormat of this Sample Provider + + + + + Read Samples from this sample provider + + + + + Sample Provider to allow fading in and out + + + + + Creates a new FadeInOutSampleProvider + + The source stream with the audio to be faded in or out + If true, we start faded out + + + + Requests that a fade-in begins (will start on the next call to Read) + + Duration of fade in milliseconds + + + + Requests that a fade-out begins (will start on the next call to Read) + + Duration of fade in milliseconds + + + + Reads samples from this sample provider + + Buffer to read into + Offset within buffer to write to + Number of samples desired + Number of samples read + + + + WaveFormat of this SampleProvider + + + + + Allows any number of inputs to be patched to outputs + Uses could include swapping left and right channels, turning mono into stereo, + feeding different input sources to different soundcard outputs etc + + + + + Creates a multiplexing sample provider, allowing re-patching of input channels to different + output channels + + Input sample providers. Must all be of the same sample rate, but can have any number of channels + Desired number of output channels. + + + + persistent temporary buffer to prevent creating work for garbage collector + + + + + Reads samples from this sample provider + + Buffer to be filled with sample data + Offset into buffer to start writing to, usually 0 + Number of samples required + Number of samples read + + + + The output WaveFormat for this SampleProvider + + + + + Connects a specified input channel to an output channel + + Input Channel index (zero based). Must be less than InputChannelCount + Output Channel index (zero based). Must be less than OutputChannelCount + + + + The number of input channels. Note that this is not the same as the number of input wave providers. If you pass in + one stereo and one mono input provider, the number of input channels is three. + + + + + The number of output channels, as specified in the constructor. + + + + + Allows you to: + 1. insert a pre-delay of silence before the source begins + 2. skip over a certain amount of the beginning of the source + 3. only play a set amount from the source + 4. insert silence at the end after the source is complete + + + + + Number of samples of silence to insert before playing source + + + + + Amount of silence to insert before playing + + + + + Number of samples in source to discard + + + + + Amount of audio to skip over from the source before beginning playback + + + + + Number of samples to read from source (if 0, then read it all) + + + + + Amount of audio to take from the source (TimeSpan.Zero means play to end) + + + + + Number of samples of silence to insert after playing source + + + + + Amount of silence to insert after playing source + + + + + Creates a new instance of offsetSampleProvider + + The Source Sample Provider to read from + + + + The WaveFormat of this SampleProvider + + + + + Reads from this sample provider + + Sample buffer + Offset within sample buffer to read to + Number of samples required + Number of samples read + + + + Converts an IWaveProvider containing 32 bit PCM to an + ISampleProvider + + + + + Initialises a new instance of Pcm32BitToSampleProvider + + Source Wave Provider + + + + Reads floating point samples from this sample provider + + sample buffer + offset within sample buffer to write to + number of samples required + number of samples provided + + + + Utility class for converting to SampleProvider + + + + + Helper function to go from IWaveProvider to a SampleProvider + Must already be PCM or IEEE float + + The WaveProvider to convert + A sample provider + + + + Converts a sample provider to 16 bit PCM, optionally clipping and adjusting volume along the way + + + + + Converts from an ISampleProvider (IEEE float) to a 16 bit PCM IWaveProvider. + Number of channels and sample rate remain unchanged. + + The input source provider + + + + Reads bytes from this wave stream + + The destination buffer + Offset into the destination buffer + Number of bytes read + Number of bytes read. + + + + + + + + + Volume of this channel. 1.0 = full scale + + + + + Converts a sample provider to 24 bit PCM, optionally clipping and adjusting volume along the way + + + + + Converts from an ISampleProvider (IEEE float) to a 16 bit PCM IWaveProvider. + Number of channels and sample rate remain unchanged. + + The input source provider + + + + Reads bytes from this wave stream, clipping if necessary + + The destination buffer + Offset into the destination buffer + Number of bytes read + Number of bytes read. + + + + The Format of this IWaveProvider + + + + + + Volume of this channel. 1.0 = full scale, 0.0 to mute + + + + + Signal Generator + Sin, Square, Triangle, SawTooth, White Noise, Pink Noise, Sweep. + + + Posibility to change ISampleProvider + Example : + --------- + WaveOut _waveOutGene = new WaveOut(); + WaveGenerator wg = new SignalGenerator(); + wg.Type = ... + wg.Frequency = ... + wg ... + _waveOutGene.Init(wg); + _waveOutGene.Play(); + + + + + Initializes a new instance for the Generator (Default :: 44.1Khz, 2 channels, Sinus, Frequency = 440, Gain = 1) + + + + + Initializes a new instance for the Generator (UserDef SampleRate & Channels) + + Desired sample rate + Number of channels + + + + The waveformat of this WaveProvider (same as the source) + + + + + Frequency for the Generator. (20.0 - 20000.0 Hz) + Sin, Square, Triangle, SawTooth, Sweep (Start Frequency). + + + + + Return Log of Frequency Start (Read only) + + + + + End Frequency for the Sweep Generator. (Start Frequency in Frequency) + + + + + Return Log of Frequency End (Read only) + + + + + Gain for the Generator. (0.0 to 1.0) + + + + + Channel PhaseReverse + + + + + Type of Generator. + + + + + Length Seconds for the Sweep Generator. + + + + + Reads from this provider. + + + + + Private :: Random for WhiteNoise & Pink Noise (Value form -1 to 1) + + Random value from -1 to +1 + + + + Signal Generator type + + + + + Pink noise + + + + + White noise + + + + + Sweep + + + + + Sine wave + + + + + Square wave + + + + + Triangle Wave + + + + + Sawtooth wave + + + + + Author: Freefall + Date: 05.08.16 + Based on: the port of Stephan M. Bernsee´s pitch shifting class + Port site: https://sites.google.com/site/mikescoderama/pitch-shifting + Test application and github site: https://github.com/Freefall63/NAudio-Pitchshifter + + NOTE: I strongly advice to add a Limiter for post-processing. + For my needs the FastAttackCompressor1175 provides acceptable results: + https://github.com/Jiyuu/SkypeFX/blob/master/JSNet/FastAttackCompressor1175.cs + + UPDATE: Added a simple Limiter based on the pydirac implementation. + https://github.com/echonest/remix/blob/master/external/pydirac225/source/Dirac_LE.cpp + + + + + + Creates a new SMB Pitch Shifting Sample Provider with default settings + + Source provider + + + + Creates a new SMB Pitch Shifting Sample Provider with custom settings + + Source provider + FFT Size (any power of two <= 4096: 4096, 2048, 1024, 512, ...) + Oversampling (number of overlapping windows) + Initial pitch (0.5f = octave down, 1.0f = normal, 2.0f = octave up) + + + + Read from this sample provider + + + + + WaveFormat + + + + + Pitch Factor (0.5f = octave down, 1.0f = normal, 2.0f = octave up) + + + + + Takes a stereo input and turns it to mono + + + + + Creates a new mono ISampleProvider based on a stereo input + + Stereo 16 bit PCM input + + + + 1.0 to mix the mono source entirely to the left channel + + + + + 1.0 to mix the mono source entirely to the right channel + + + + + Output Wave Format + + + + + Reads bytes from this SampleProvider + + + + + Helper class turning an already 64 bit floating point IWaveProvider + into an ISampleProvider - hopefully not needed for most applications + + + + + Initializes a new instance of the WaveToSampleProvider class + + Source wave provider, must be IEEE float + + + + Reads from this provider + + + + + Fully managed resampling sample provider, based on the WDL Resampler + + + + + Constructs a new resampler + + Source to resample + Desired output sample rate + + + + Reads from this sample provider + + + + + Output WaveFormat + + + + + Sample provider interface to make WaveChannel32 extensible + Still a bit ugly, hence internal at the moment - and might even make these into + bit depth converting WaveProviders + + + + + A sample provider mixer, allowing inputs to be added and removed + + + + + Creates a new MixingSampleProvider, with no inputs, but a specified WaveFormat + + The WaveFormat of this mixer. All inputs must be in this format + + + + Creates a new MixingSampleProvider, based on the given inputs + + Mixer inputs - must all have the same waveformat, and must + all be of the same WaveFormat. There must be at least one input + + + + Returns the mixer inputs (read-only - use AddMixerInput to add an input + + + + + When set to true, the Read method always returns the number + of samples requested, even if there are no inputs, or if the + current inputs reach their end. Setting this to true effectively + makes this a never-ending sample provider, so take care if you plan + to write it out to a file. + + + + + Adds a WaveProvider as a Mixer input. + Must be PCM or IEEE float already + + IWaveProvider mixer input + + + + Adds a new mixer input + + Mixer input + + + + Raised when a mixer input has been removed because it has ended + + + + + Removes a mixer input + + Mixer input to remove + + + + Removes all mixer inputs + + + + + The output WaveFormat of this sample provider + + + + + Reads samples from this sample provider + + Sample buffer + Offset into sample buffer + Number of samples required + Number of samples read + + + + SampleProvider event args + + + + + Constructs a new SampleProviderEventArgs + + + + + The Sample Provider + + + + + Converts a mono sample provider to stereo, with a customisable pan strategy + + + + + Initialises a new instance of the PanningSampleProvider + + Source sample provider, must be mono + + + + Pan value, must be between -1 (left) and 1 (right) + + + + + The pan strategy currently in use + + + + + The WaveFormat of this sample provider + + + + + Reads samples from this sample provider + + Sample buffer + Offset into sample buffer + Number of samples desired + Number of samples read + + + + Pair of floating point values, representing samples or multipliers + + + + + Left value + + + + + Right value + + + + + Required Interface for a Panning Strategy + + + + + Gets the left and right multipliers for a given pan value + + Pan value from -1 to 1 + Left and right multipliers in a stereo sample pair + + + + Simplistic "balance" control - treating the mono input as if it was stereo + In the centre, both channels full volume. Opposite channel decays linearly + as balance is turned to to one side + + + + + Gets the left and right channel multipliers for this pan value + + Pan value, between -1 and 1 + Left and right multipliers + + + + Square Root Pan, thanks to Yuval Naveh + + + + + Gets the left and right channel multipliers for this pan value + + Pan value, between -1 and 1 + Left and right multipliers + + + + Sinus Pan, thanks to Yuval Naveh + + + + + Gets the left and right channel multipliers for this pan value + + Pan value, between -1 and 1 + Left and right multipliers + + + + Linear Pan + + + + + Gets the left and right channel multipliers for this pan value + + Pan value, between -1 and 1 + Left and right multipliers + + + + Simple SampleProvider that passes through audio unchanged and raises + an event every n samples with the maximum sample value from the period + for metering purposes + + + + + Number of Samples per notification + + + + + Raised periodically to inform the user of the max volume + + + + + Initialises a new instance of MeteringSampleProvider that raises 10 stream volume + events per second + + Source sample provider + + + + Initialises a new instance of MeteringSampleProvider + + source sampler provider + Number of samples between notifications + + + + The WaveFormat of this sample provider + + + + + Reads samples from this Sample Provider + + Sample buffer + Offset into sample buffer + Number of samples required + Number of samples read + + + + Event args for aggregated stream volume + + + + + Max sample values array (one for each channel) + + + + + Simple class that raises an event on every sample + + + + + Initializes a new instance of NotifyingSampleProvider + + Source Sample Provider + + + + WaveFormat + + + + + Reads samples from this sample provider + + Sample buffer + Offset into sample buffer + Number of samples desired + Number of samples read + + + + Sample notifier + + + + + Very simple sample provider supporting adjustable gain + + + + + Initializes a new instance of VolumeSampleProvider + + Source Sample Provider + + + + WaveFormat + + + + + Reads samples from this sample provider + + Sample buffer + Offset into sample buffer + Number of samples desired + Number of samples read + + + + Allows adjusting the volume, 1.0f = full volume + + + + + Helper base class for classes converting to ISampleProvider + + + + + Source Wave Provider + + + + + Source buffer (to avoid constantly creating small buffers during playback) + + + + + Initialises a new instance of SampleProviderConverterBase + + Source Wave provider + + + + Wave format of this wave provider + + + + + Reads samples from the source wave provider + + Sample buffer + Offset into sample buffer + Number of samples required + Number of samples read + + + + Ensure the source buffer exists and is big enough + + Bytes required + + + + Helper class for when you need to convert back to an IWaveProvider from + an ISampleProvider. Keeps it as IEEE float + + + + + Initializes a new instance of the WaveProviderFloatToWaveProvider class + + Source wave provider + + + + Reads from this provider + + + + + The waveformat of this WaveProvider (same as the source) + + + + + No nonsense mono to stereo provider, no volume adjustment, + just copies input to left and right. + + + + + Initializes a new instance of MonoToStereoSampleProvider + + Source sample provider + + + + WaveFormat of this provider + + + + + Reads samples from this provider + + Sample buffer + Offset into sample buffer + Number of samples required + Number of samples read + + + + Multiplier for left channel (default is 1.0) + + + + + Multiplier for right channel (default is 1.0) + + + + + Helper class turning an already 32 bit floating point IWaveProvider + into an ISampleProvider - hopefully not needed for most applications + + + + + Initializes a new instance of the WaveToSampleProvider class + + Source wave provider, must be IEEE float + + + + Reads from this provider + + + + + Converts an IWaveProvider containing 16 bit PCM to an + ISampleProvider + + + + + Initialises a new instance of Pcm16BitToSampleProvider + + Source wave provider + + + + Reads samples from this sample provider + + Sample buffer + Offset into sample buffer + Samples required + Number of samples read + + + + Converts an IWaveProvider containing 24 bit PCM to an + ISampleProvider + + + + + Initialises a new instance of Pcm24BitToSampleProvider + + Source Wave Provider + + + + Reads floating point samples from this sample provider + + sample buffer + offset within sample buffer to write to + number of samples required + number of samples provided + + + + Converts an IWaveProvider containing 8 bit PCM to an + ISampleProvider + + + + + Initialises a new instance of Pcm8BitToSampleProvider + + Source wave provider + + + + Reads samples from this sample provider + + Sample buffer + Offset into sample buffer + Number of samples to read + Number of samples read + + + + Utility class that takes an IWaveProvider input at any bit depth + and exposes it as an ISampleProvider. Can turn mono inputs into stereo, + and allows adjusting of volume + (The eventual successor to WaveChannel32) + This class also serves as an example of how you can link together several simple + Sample Providers to form a more useful class. + + + + + Initialises a new instance of SampleChannel + + Source wave provider, must be PCM or IEEE + + + + Initialises a new instance of SampleChannel + + Source wave provider, must be PCM or IEEE + force mono inputs to become stereo + + + + Reads samples from this sample provider + + Sample buffer + Offset into sample buffer + Number of samples desired + Number of samples read + + + + The WaveFormat of this Sample Provider + + + + + Allows adjusting the volume, 1.0f = full volume + + + + + Raised periodically to inform the user of the max volume + (before the volume meter) + + + + + Useful extension methods to make switching between WaveAndSampleProvider easier + + + + + Converts a WaveProvider into a SampleProvider (only works for PCM) + + WaveProvider to convert + + + + + Allows sending a SampleProvider directly to an IWavePlayer without needing to convert + back to an IWaveProvider + + The WavePlayer + + + + + + Turns WaveFormatExtensible into a standard waveformat if possible + + Input wave format + A standard PCM or IEEE waveformat, or the original waveformat + + + + Converts a ISampleProvider to a IWaveProvider but still 32 bit float + + SampleProvider to convert + An IWaveProvider + + + + Converts a ISampleProvider to a IWaveProvider but and convert to 16 bit + + SampleProvider to convert + A 16 bit IWaveProvider + + + + Concatenates one Sample Provider on the end of another + + The sample provider to play first + The sample provider to play next + A single sampleprovider to play one after the other + + + + Concatenates one Sample Provider on the end of another with silence inserted + + The sample provider to play first + Silence duration to insert between the two + The sample provider to play next + A single sample provider + + + + Skips over a specified amount of time (by consuming source stream) + + Source sample provider + Duration to skip over + A sample provider that skips over the specified amount of time + + + + Takes a specified amount of time from the source stream + + Source sample provider + Duration to take + A sample provider that reads up to the specified amount of time + + + + Converts a Stereo Sample Provider to mono, allowing mixing of channel volume + + Stereo Source Provider + Amount of left channel to mix in (0 = mute, 1 = full, 0.5 for mixing half from each channel) + Amount of right channel to mix in (0 = mute, 1 = full, 0.5 for mixing half from each channel) + A mono SampleProvider + + + + Converts a Mono ISampleProvider to stereo + + Mono Source Provider + Amount to mix to left channel (1.0 is full volume) + Amount to mix to right channel (1.0 is full volume) + + + + + Recording using waveIn api with event callbacks. + Use this for recording in non-gui applications + Events are raised as recorded buffers are made available + + + + + Indicates recorded data is available + + + + + Indicates that all recorded data has now been received. + + + + + Prepares a Wave input device for recording + + + + + Returns the number of Wave In devices available in the system + + + + + Retrieves the capabilities of a waveIn device + + Device to test + The WaveIn device capabilities + + + + Milliseconds for the buffer. Recommended value is 100ms + + + + + Number of Buffers to use (usually 2 or 3) + + + + + The device number to use + + + + + Start recording + + + + + Stop recording + + + + + WaveFormat we are recording in + + + + + Dispose pattern + + + + + Microphone Level + + + + + Dispose method + + + + + Channel Mode + + + + + Stereo + + + + + Joint Stereo + + + + + Dual Channel + + + + + Mono + + + + + An ID3v2 Tag + + + + + Reads an ID3v2 tag from a stream + + + + + Creates a new ID3v2 tag from a collection of key-value pairs. + + A collection of key-value pairs containing the tags to include in the ID3v2 tag. + A new ID3v2 tag + + + + Convert the frame size to a byte array. + + The frame body size. + + + + + Creates an ID3v2 frame for the given key-value pair. + + + + + + + + Gets the Id3v2 Header size. The size is encoded so that only 7 bits per byte are actually used. + + + + + + + Creates the Id3v2 tag header and returns is as a byte array. + + The Id3v2 frames that will be included in the file. This is used to calculate the ID3v2 tag size. + + + + + Creates the Id3v2 tag for the given key-value pairs and returns it in the a stream. + + + + + + + Raw data from this tag + + + + + Interface for MP3 frame by frame decoder + + + + + Decompress a single MP3 frame + + Frame to decompress + Output buffer + Offset within output buffer + Bytes written to output buffer + + + + Tell the decoder that we have repositioned + + + + + PCM format that we are converting into + + + + + Represents an MP3 Frame + + + + + Reads an MP3 frame from a stream + + input stream + A valid MP3 frame, or null if none found + + + Reads an MP3Frame from a stream + http://mpgedit.org/mpgedit/mpeg_format/mpeghdr.htm has some good info + also see http://www.codeproject.com/KB/audio-video/mpegaudioinfo.aspx + + A valid MP3 frame, or null if none found + + + + Constructs an MP3 frame + + + + + checks if the four bytes represent a valid header, + if they are, will parse the values into Mp3Frame + + + + + Sample rate of this frame + + + + + Frame length in bytes + + + + + Bit Rate + + + + + Raw frame data (includes header bytes) + + + + + MPEG Version + + + + + MPEG Layer + + + + + Channel Mode + + + + + The number of samples in this frame + + + + + The channel extension bits + + + + + The bitrate index (directly from the header) + + + + + Whether the Copyright bit is set + + + + + Whether a CRC is present + + + + + Not part of the MP3 frame itself - indicates where in the stream we found this header + + + + + MP3 Frame Decompressor using ACM + + + + + Creates a new ACM frame decompressor + + The MP3 source format + + + + Output format (PCM) + + + + + Decompresses a frame + + The MP3 frame + destination buffer + Offset within destination buffer + Bytes written into destination buffer + + + + Resets the MP3 Frame Decompressor after a reposition operation + + + + + Disposes of this MP3 frame decompressor + + + + + Finalizer ensuring that resources get released properly + + + + + MPEG Layer flags + + + + + Reserved + + + + + Layer 3 + + + + + Layer 2 + + + + + Layer 1 + + + + + MPEG Version Flags + + + + + Version 2.5 + + + + + Reserved + + + + + Version 2 + + + + + Version 1 + + + + + Represents a Xing VBR header + + + + + Load Xing Header + + Frame + Xing Header + + + + Sees if a frame contains a Xing header + + + + + Number of frames + + + + + Number of bytes + + + + + VBR Scale property + + + + + The MP3 frame + + + + ACM_METRIC_COUNT_DRIVERS + + + ACM_METRIC_COUNT_CODECS + + + ACM_METRIC_COUNT_CONVERTERS + + + ACM_METRIC_COUNT_FILTERS + + + ACM_METRIC_COUNT_DISABLED + + + ACM_METRIC_COUNT_HARDWARE + + + ACM_METRIC_COUNT_LOCAL_DRIVERS + + + ACM_METRIC_COUNT_LOCAL_CODECS + + + ACM_METRIC_COUNT_LOCAL_CONVERTERS + + + ACM_METRIC_COUNT_LOCAL_FILTERS + + + ACM_METRIC_COUNT_LOCAL_DISABLED + + + ACM_METRIC_HARDWARE_WAVE_INPUT + + + ACM_METRIC_HARDWARE_WAVE_OUTPUT + + + ACM_METRIC_MAX_SIZE_FORMAT + + + ACM_METRIC_MAX_SIZE_FILTER + + + ACM_METRIC_DRIVER_SUPPORT + + + ACM_METRIC_DRIVER_PRIORITY + + + + ACM_STREAMCONVERTF_BLOCKALIGN + + + + + ACM_STREAMCONVERTF_START + + + + + ACM_STREAMCONVERTF_END + + + + + WaveHeader interop structure (WAVEHDR) + http://msdn.microsoft.com/en-us/library/dd743837%28VS.85%29.aspx + + + + pointer to locked data buffer (lpData) + + + length of data buffer (dwBufferLength) + + + used for input only (dwBytesRecorded) + + + for client's use (dwUser) + + + assorted flags (dwFlags) + + + loop control counter (dwLoops) + + + PWaveHdr, reserved for driver (lpNext) + + + reserved for driver + + + + Wave Header Flags enumeration + + + + + WHDR_BEGINLOOP + This buffer is the first buffer in a loop. This flag is used only with output buffers. + + + + + WHDR_DONE + Set by the device driver to indicate that it is finished with the buffer and is returning it to the application. + + + + + WHDR_ENDLOOP + This buffer is the last buffer in a loop. This flag is used only with output buffers. + + + + + WHDR_INQUEUE + Set by Windows to indicate that the buffer is queued for playback. + + + + + WHDR_PREPARED + Set by Windows to indicate that the buffer has been prepared with the waveInPrepareHeader or waveOutPrepareHeader function. + + + + + WASAPI Loopback Capture + based on a contribution from "Pygmy" - http://naudio.codeplex.com/discussions/203605 + + + + + Initialises a new instance of the WASAPI capture class + + + + + Initialises a new instance of the WASAPI capture class + + Capture device to use + + + + Gets the default audio loopback capture device + + The default audio loopback capture device + + + + Capturing wave format + + + + + Specify loopback + + + + + Allows recording using the Windows waveIn APIs + Events are raised as recorded buffers are made available + + + + + Indicates recorded data is available + + + + + Indicates that all recorded data has now been received. + + + + + Prepares a Wave input device for recording + + + + + Creates a WaveIn device using the specified window handle for callbacks + + A valid window handle + + + + Prepares a Wave input device for recording + + + + + Returns the number of Wave In devices available in the system + + + + + Retrieves the capabilities of a waveIn device + + Device to test + The WaveIn device capabilities + + + + Milliseconds for the buffer. Recommended value is 100ms + + + + + Number of Buffers to use (usually 2 or 3) + + + + + The device number to use + + + + + Called when we get a new buffer of recorded data + + + + + Start recording + + + + + Stop recording + + + + + WaveFormat we are recording in + + + + + Dispose pattern + + + + + Microphone Level + + + + + Dispose method + + + + + WaveInCapabilities structure (based on WAVEINCAPS2 from mmsystem.h) + http://msdn.microsoft.com/en-us/library/ms713726(VS.85).aspx + + + + + wMid + + + + + wPid + + + + + vDriverVersion + + + + + Product Name (szPname) + + + + + Supported formats (bit flags) dwFormats + + + + + Supported channels (1 for mono 2 for stereo) (wChannels) + Seems to be set to -1 on a lot of devices + + + + + wReserved1 + + + + + Number of channels supported + + + + + The product name + + + + + The device name Guid (if provided) + + + + + The product name Guid (if provided) + + + + + The manufacturer guid (if provided) + + + + + Checks to see if a given SupportedWaveFormat is supported + + The SupportedWaveFormat + true if supported + + + + The device name from the registry if supported + + + + + Event Args for WaveInStream event + + + + + Creates new WaveInEventArgs + + + + + Buffer containing recorded data. Note that it might not be completely + full. + + + + + The number of recorded bytes in Buffer. + + + + + MME Wave function interop + + + + + CALLBACK_NULL + No callback + + + + + CALLBACK_FUNCTION + dwCallback is a FARPROC + + + + + CALLBACK_EVENT + dwCallback is an EVENT handle + + + + + CALLBACK_WINDOW + dwCallback is a HWND + + + + + CALLBACK_THREAD + callback is a thread ID + + + + + WIM_OPEN + + + + + WIM_CLOSE + + + + + WIM_DATA + + + + + WOM_CLOSE + + + + + WOM_DONE + + + + + WOM_OPEN + + + + + WaveOutCapabilities structure (based on WAVEOUTCAPS2 from mmsystem.h) + http://msdn.microsoft.com/library/default.asp?url=/library/en-us/multimed/htm/_win32_waveoutcaps_str.asp + + + + + wMid + + + + + wPid + + + + + vDriverVersion + + + + + Product Name (szPname) + + + + + Supported formats (bit flags) dwFormats + + + + + Supported channels (1 for mono 2 for stereo) (wChannels) + Seems to be set to -1 on a lot of devices + + + + + wReserved1 + + + + + Optional functionality supported by the device + + + + + Number of channels supported + + + + + Whether playback control is supported + + + + + The product name + + + + + Checks to see if a given SupportedWaveFormat is supported + + The SupportedWaveFormat + true if supported + + + + The device name Guid (if provided) + + + + + The product name Guid (if provided) + + + + + The manufacturer guid (if provided) + + + + + Supported wave formats for WaveOutCapabilities + + + + + 11.025 kHz, Mono, 8-bit + + + + + 11.025 kHz, Stereo, 8-bit + + + + + 11.025 kHz, Mono, 16-bit + + + + + 11.025 kHz, Stereo, 16-bit + + + + + 22.05 kHz, Mono, 8-bit + + + + + 22.05 kHz, Stereo, 8-bit + + + + + 22.05 kHz, Mono, 16-bit + + + + + 22.05 kHz, Stereo, 16-bit + + + + + 44.1 kHz, Mono, 8-bit + + + + + 44.1 kHz, Stereo, 8-bit + + + + + 44.1 kHz, Mono, 16-bit + + + + + 44.1 kHz, Stereo, 16-bit + + + + + 44.1 kHz, Mono, 8-bit + + + + + 44.1 kHz, Stereo, 8-bit + + + + + 44.1 kHz, Mono, 16-bit + + + + + 44.1 kHz, Stereo, 16-bit + + + + + 48 kHz, Mono, 8-bit + + + + + 48 kHz, Stereo, 8-bit + + + + + 48 kHz, Mono, 16-bit + + + + + 48 kHz, Stereo, 16-bit + + + + + 96 kHz, Mono, 8-bit + + + + + 96 kHz, Stereo, 8-bit + + + + + 96 kHz, Mono, 16-bit + + + + + 96 kHz, Stereo, 16-bit + + + + + Flags indicating what features this WaveOut device supports + + + + supports pitch control (WAVECAPS_PITCH) + + + supports playback rate control (WAVECAPS_PLAYBACKRATE) + + + supports volume control (WAVECAPS_VOLUME) + + + supports separate left-right volume control (WAVECAPS_LRVOLUME) + + + (WAVECAPS_SYNC) + + + (WAVECAPS_SAMPLEACCURATE) + + + + GSM 610 + + + + + Creates a GSM 610 WaveFormat + For now hardcoded to 13kbps + + + + + Samples per block + + + + + Writes this structure to a BinaryWriter + + + + + IMA/DVI ADPCM Wave Format + Work in progress + + + + + parameterless constructor for Marshalling + + + + + Creates a new IMA / DVI ADPCM Wave Format + + Sample Rate + Number of channels + Bits Per Sample + + + + MP3 WaveFormat, MPEGLAYER3WAVEFORMAT from mmreg.h + + + + + Wave format ID (wID) + + + + + Padding flags (fdwFlags) + + + + + Block Size (nBlockSize) + + + + + Frames per block (nFramesPerBlock) + + + + + Codec Delay (nCodecDelay) + + + + + Creates a new MP3 WaveFormat + + + + + Wave Format Padding Flags + + + + + MPEGLAYER3_FLAG_PADDING_ISO + + + + + MPEGLAYER3_FLAG_PADDING_ON + + + + + MPEGLAYER3_FLAG_PADDING_OFF + + + + + Wave Format ID + + + + MPEGLAYER3_ID_UNKNOWN + + + MPEGLAYER3_ID_MPEG + + + MPEGLAYER3_ID_CONSTANTFRAMESIZE + + + + DSP Group TrueSpeech + + + + + DSP Group TrueSpeech WaveFormat + + + + + Writes this structure to a BinaryWriter + + + + + Represents a Wave file format + + + + format type + + + number of channels + + + sample rate + + + for buffer estimation + + + block size of data + + + number of bits per sample of mono data + + + number of following bytes + + + + Creates a new PCM 44.1Khz stereo 16 bit format + + + + + Creates a new 16 bit wave format with the specified sample + rate and channel count + + Sample Rate + Number of channels + + + + Gets the size of a wave buffer equivalent to the latency in milliseconds. + + The milliseconds. + + + + + Creates a WaveFormat with custom members + + The encoding + Sample Rate + Number of channels + Average Bytes Per Second + Block Align + Bits Per Sample + + + + + Creates an A-law wave format + + Sample Rate + Number of Channels + Wave Format + + + + Creates a Mu-law wave format + + Sample Rate + Number of Channels + Wave Format + + + + Creates a new PCM format with the specified sample rate, bit depth and channels + + + + + Creates a new 32 bit IEEE floating point wave format + + sample rate + number of channels + + + + Helper function to retrieve a WaveFormat structure from a pointer + + WaveFormat structure + + + + + Helper function to marshal WaveFormat to an IntPtr + + WaveFormat + IntPtr to WaveFormat structure (needs to be freed by callee) + + + + Reads in a WaveFormat (with extra data) from a fmt chunk (chunk identifier and + length should already have been read) + + Binary reader + Format chunk length + A WaveFormatExtraData + + + + Reads a new WaveFormat object from a stream + + A binary reader that wraps the stream + + + + Reports this WaveFormat as a string + + String describing the wave format + + + + Compares with another WaveFormat object + + Object to compare to + True if the objects are the same + + + + Provides a Hashcode for this WaveFormat + + A hashcode + + + + Returns the encoding type used + + + + + Writes this WaveFormat object to a stream + + the output stream + + + + Returns the number of channels (1=mono,2=stereo etc) + + + + + Returns the sample rate (samples per second) + + + + + Returns the average number of bytes used per second + + + + + Returns the block alignment + + + + + Returns the number of bits per sample (usually 16 or 32, sometimes 24 or 8) + Can be 0 for some codecs + + + + + Returns the number of extra bytes used by this waveformat. Often 0, + except for compressed formats which store extra data after the WAVEFORMATEX header + + + + + Microsoft ADPCM + See http://icculus.org/SDL_sound/downloads/external_documentation/wavecomp.htm + + + + + Empty constructor needed for marshalling from a pointer + + + + + Samples per block + + + + + Number of coefficients + + + + + Coefficients + + + + + Microsoft ADPCM + + Sample Rate + Channels + + + + Serializes this wave format + + Binary writer + + + + String Description of this WaveFormat + + + + + Custom marshaller for WaveFormat structures + + + + + Gets the instance of this marshaller + + + + + + + Clean up managed data + + + + + Clean up native data + + + + + + Get native data size + + + + + Marshal managed to native + + + + + Marshal Native to Managed + + + + + Summary description for WaveFormatEncoding. + + + + WAVE_FORMAT_UNKNOWN, Microsoft Corporation + + + WAVE_FORMAT_PCM Microsoft Corporation + + + WAVE_FORMAT_ADPCM Microsoft Corporation + + + WAVE_FORMAT_IEEE_FLOAT Microsoft Corporation + + + WAVE_FORMAT_VSELP Compaq Computer Corp. + + + WAVE_FORMAT_IBM_CVSD IBM Corporation + + + WAVE_FORMAT_ALAW Microsoft Corporation + + + WAVE_FORMAT_MULAW Microsoft Corporation + + + WAVE_FORMAT_DTS Microsoft Corporation + + + WAVE_FORMAT_DRM Microsoft Corporation + + + WAVE_FORMAT_WMAVOICE9 + + + WAVE_FORMAT_OKI_ADPCM OKI + + + WAVE_FORMAT_DVI_ADPCM Intel Corporation + + + WAVE_FORMAT_IMA_ADPCM Intel Corporation + + + WAVE_FORMAT_MEDIASPACE_ADPCM Videologic + + + WAVE_FORMAT_SIERRA_ADPCM Sierra Semiconductor Corp + + + WAVE_FORMAT_G723_ADPCM Antex Electronics Corporation + + + WAVE_FORMAT_DIGISTD DSP Solutions, Inc. + + + WAVE_FORMAT_DIGIFIX DSP Solutions, Inc. + + + WAVE_FORMAT_DIALOGIC_OKI_ADPCM Dialogic Corporation + + + WAVE_FORMAT_MEDIAVISION_ADPCM Media Vision, Inc. + + + WAVE_FORMAT_CU_CODEC Hewlett-Packard Company + + + WAVE_FORMAT_YAMAHA_ADPCM Yamaha Corporation of America + + + WAVE_FORMAT_SONARC Speech Compression + + + WAVE_FORMAT_DSPGROUP_TRUESPEECH DSP Group, Inc + + + WAVE_FORMAT_ECHOSC1 Echo Speech Corporation + + + WAVE_FORMAT_AUDIOFILE_AF36, Virtual Music, Inc. + + + WAVE_FORMAT_APTX Audio Processing Technology + + + WAVE_FORMAT_AUDIOFILE_AF10, Virtual Music, Inc. + + + WAVE_FORMAT_PROSODY_1612, Aculab plc + + + WAVE_FORMAT_LRC, Merging Technologies S.A. + + + WAVE_FORMAT_DOLBY_AC2, Dolby Laboratories + + + WAVE_FORMAT_GSM610, Microsoft Corporation + + + WAVE_FORMAT_MSNAUDIO, Microsoft Corporation + + + WAVE_FORMAT_ANTEX_ADPCME, Antex Electronics Corporation + + + WAVE_FORMAT_CONTROL_RES_VQLPC, Control Resources Limited + + + WAVE_FORMAT_DIGIREAL, DSP Solutions, Inc. + + + WAVE_FORMAT_DIGIADPCM, DSP Solutions, Inc. + + + WAVE_FORMAT_CONTROL_RES_CR10, Control Resources Limited + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + WAVE_FORMAT_MPEG, Microsoft Corporation + + + + + + + + + WAVE_FORMAT_MPEGLAYER3, ISO/MPEG Layer3 Format Tag + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + WAVE_FORMAT_GSM + + + WAVE_FORMAT_G729 + + + WAVE_FORMAT_G723 + + + WAVE_FORMAT_ACELP + + + + WAVE_FORMAT_RAW_AAC1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Windows Media Audio, WAVE_FORMAT_WMAUDIO2, Microsoft Corporation + + + + + Windows Media Audio Professional WAVE_FORMAT_WMAUDIO3, Microsoft Corporation + + + + + Windows Media Audio Lossless, WAVE_FORMAT_WMAUDIO_LOSSLESS + + + + + Windows Media Audio Professional over SPDIF WAVE_FORMAT_WMASPDIF (0x0164) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Advanced Audio Coding (AAC) audio in Audio Data Transport Stream (ADTS) format. + The format block is a WAVEFORMATEX structure with wFormatTag equal to WAVE_FORMAT_MPEG_ADTS_AAC. + + + The WAVEFORMATEX structure specifies the core AAC-LC sample rate and number of channels, + prior to applying spectral band replication (SBR) or parametric stereo (PS) tools, if present. + No additional data is required after the WAVEFORMATEX structure. + + http://msdn.microsoft.com/en-us/library/dd317599%28VS.85%29.aspx + + + + Source wmCodec.h + + + + MPEG-4 audio transport stream with a synchronization layer (LOAS) and a multiplex layer (LATM). + The format block is a WAVEFORMATEX structure with wFormatTag equal to WAVE_FORMAT_MPEG_LOAS. + + + The WAVEFORMATEX structure specifies the core AAC-LC sample rate and number of channels, + prior to applying spectral SBR or PS tools, if present. + No additional data is required after the WAVEFORMATEX structure. + + http://msdn.microsoft.com/en-us/library/dd317599%28VS.85%29.aspx + + + NOKIA_MPEG_ADTS_AAC + Source wmCodec.h + + + NOKIA_MPEG_RAW_AAC + Source wmCodec.h + + + VODAFONE_MPEG_ADTS_AAC + Source wmCodec.h + + + VODAFONE_MPEG_RAW_AAC + Source wmCodec.h + + + + High-Efficiency Advanced Audio Coding (HE-AAC) stream. + The format block is an HEAACWAVEFORMAT structure. + + http://msdn.microsoft.com/en-us/library/dd317599%28VS.85%29.aspx + + + WAVE_FORMAT_DVM + + + WAVE_FORMAT_VORBIS1 "Og" Original stream compatible + + + WAVE_FORMAT_VORBIS2 "Pg" Have independent header + + + WAVE_FORMAT_VORBIS3 "Qg" Have no codebook header + + + WAVE_FORMAT_VORBIS1P "og" Original stream compatible + + + WAVE_FORMAT_VORBIS2P "pg" Have independent headere + + + WAVE_FORMAT_VORBIS3P "qg" Have no codebook header + + + WAVE_FORMAT_EXTENSIBLE + + + + + + + WaveFormatExtensible + http://www.microsoft.com/whdc/device/audio/multichaud.mspx + + + + + Parameterless constructor for marshalling + + + + + Creates a new WaveFormatExtensible for PCM or IEEE + + + + + WaveFormatExtensible for PCM or floating point can be awkward to work with + This creates a regular WaveFormat structure representing the same audio format + Returns the WaveFormat unchanged for non PCM or IEEE float + + + + + + SubFormat (may be one of AudioMediaSubtypes) + + + + + Serialize + + + + + + String representation + + + + + This class used for marshalling from unmanaged code + + + + + Allows the extra data to be read + + + + + parameterless constructor for marshalling + + + + + Reads this structure from a BinaryReader + + + + + Writes this structure to a BinaryWriter + + + + + The WMA wave format. + May not be much use because WMA codec is a DirectShow DMO not an ACM + + + + + Generic interface for wave recording + + + + + Recording WaveFormat + + + + + Start Recording + + + + + Stop Recording + + + + + Indicates recorded data is available + + + + + Indicates that all recorded data has now been received. + + + + + This class writes audio data to a .aif file on disk + + + + + Creates an Aiff file by reading all the data from a WaveProvider + BEWARE: the WaveProvider MUST return 0 from its Read method when it is finished, + or the Aiff File will grow indefinitely. + + The filename to use + The source WaveProvider + + + + AiffFileWriter that actually writes to a stream + + Stream to be written to + Wave format to use + + + + Creates a new AiffFileWriter + + The filename to write to + The Wave Format of the output data + + + + The aiff file name or null if not applicable + + + + + Number of bytes of audio in the data chunk + + + + + WaveFormat of this aiff file + + + + + Returns false: Cannot read from a AiffFileWriter + + + + + Returns true: Can write to a AiffFileWriter + + + + + Returns false: Cannot seek within a AiffFileWriter + + + + + Read is not supported for a AiffFileWriter + + + + + Seek is not supported for a AiffFileWriter + + + + + SetLength is not supported for AiffFileWriter + + + + + + Gets the Position in the AiffFile (i.e. number of bytes written so far) + + + + + Appends bytes to the AiffFile (assumes they are already in the correct format) + + the buffer containing the wave data + the offset from which to start writing + the number of bytes to write + + + + Writes a single sample to the Aiff file + + the sample to write (assumed floating point with 1.0f as max value) + + + + Writes 32 bit floating point samples to the Aiff file + They will be converted to the appropriate bit depth depending on the WaveFormat of the AIF file + + The buffer containing the floating point samples + The offset from which to start writing + The number of floating point samples to write + + + + Writes 16 bit samples to the Aiff file + + The buffer containing the 16 bit samples + The offset from which to start writing + The number of 16 bit samples to write + + + + Ensures data is written to disk + + + + + Actually performs the close,making sure the header contains the correct data + + True if called from Dispose + + + + Updates the header with file size information + + + + + Finaliser - should only be called if the user forgot to close this AiffFileWriter + + + + + Raised when ASIO data has been recorded. + It is important to handle this as quickly as possible as it is in the buffer callback + + + + + Initialises a new instance of AsioAudioAvailableEventArgs + + Pointers to the ASIO buffers for each channel + Pointers to the ASIO buffers for each channel + Number of samples in each buffer + Audio format within each buffer + + + + Pointer to a buffer per input channel + + + + + Pointer to a buffer per output channel + Allows you to write directly to the output buffers + If you do so, set SamplesPerBuffer = true, + and make sure all buffers are written to with valid data + + + + + Set to true if you have written to the output buffers + If so, AsioOut will not read from its source + + + + + Number of samples in each buffer + + + + + Converts all the recorded audio into a buffer of 32 bit floating point samples, interleaved by channel + + The samples as 32 bit floating point, interleaved + + + + Audio format within each buffer + Most commonly this will be one of, Int32LSB, Int16LSB, Int24LSB or Float32LSB + + + + + Gets as interleaved samples, allocating a float array + + The samples as 32 bit floating point values + + + + ASIO Out Player. New implementation using an internal C# binding. + + This implementation is only supporting Short16Bit and Float32Bit formats and is optimized + for 2 outputs channels . + SampleRate is supported only if AsioDriver is supporting it + + This implementation is probably the first AsioDriver binding fully implemented in C#! + + Original Contributor: Mark Heath + New Contributor to C# binding : Alexandre Mutel - email: alexandre_mutel at yahoo.fr + + + + + Playback Stopped + + + + + When recording, fires whenever recorded audio is available + + + + + Initializes a new instance of the class with the first + available ASIO Driver. + + + + + Initializes a new instance of the class with the driver name. + + Name of the device. + + + + Opens an ASIO output device + + Device number (zero based) + + + + Releases unmanaged resources and performs other cleanup operations before the + is reclaimed by garbage collection. + + + + + Dispose + + + + + Gets the names of the installed ASIO Driver. + + an array of driver names + + + + Determines whether ASIO is supported. + + + true if ASIO is supported; otherwise, false. + + + + + Inits the driver from the asio driver name. + + Name of the driver. + + + + Shows the control panel + + + + + Starts playback + + + + + Stops playback + + + + + Pauses playback + + + + + Initialises to play + + Source wave provider + + + + Initialises to play, with optional recording + + Source wave provider - set to null for record only + Number of channels to record + Specify sample rate here if only recording, ignored otherwise + + + + driver buffer update callback to fill the wave buffer. + + The input channels. + The output channels. + + + + Gets the latency (in ms) of the playback driver + + + + + Playback State + + + + + Driver Name + + + + + The number of output channels we are currently using for playback + (Must be less than or equal to DriverOutputChannelCount) + + + + + The number of input channels we are currently recording from + (Must be less than or equal to DriverInputChannelCount) + + + + + The maximum number of input channels this ASIO driver supports + + + + + The maximum number of output channels this ASIO driver supports + + + + + By default the first channel on the input WaveProvider is sent to the first ASIO output. + This option sends it to the specified channel number. + Warning: make sure you don't set it higher than the number of available output channels - + the number of source channels. + n.b. Future NAudio may modify this + + + + + Input channel offset (used when recording), allowing you to choose to record from just one + specific input rather than them all + + + + + Sets the volume (1.0 is unity gain) + Not supported for ASIO Out. Set the volume on the input stream instead + + + + + Get the input channel name + + channel index (zero based) + channel name + + + + Get the output channel name + + channel index (zero based) + channel name + + + + A wave file writer that adds cue support + + + + + Writes a wave file, including a cues chunk + + + + + Adds a cue to the Wave file + + Sample position + Label text + + + + Updates the header, and writes the cues out + + + + + Media Foundation Encoder class allows you to use Media Foundation to encode an IWaveProvider + to any supported encoding format + + + + + Queries the available bitrates for a given encoding output type, sample rate and number of channels + + Audio subtype - a value from the AudioSubtypes class + The sample rate of the PCM to encode + The number of channels of the PCM to encode + An array of available bitrates in average bits per second + + + + Gets all the available media types for a particular + + Audio subtype - a value from the AudioSubtypes class + An array of available media types that can be encoded with this subtype + + + + Helper function to simplify encoding Window Media Audio + Should be supported on Vista and above (not tested) + + Input provider, must be PCM + Output file path, should end with .wma + Desired bitrate. Use GetEncodeBitrates to find the possibilities for your input type + + + + Helper function to simplify encoding to MP3 + By default, will only be available on Windows 8 and above + + Input provider, must be PCM + Output file path, should end with .mp3 + Desired bitrate. Use GetEncodeBitrates to find the possibilities for your input type + + + + Helper function to simplify encoding to AAC + By default, will only be available on Windows 7 and above + + Input provider, must be PCM + Output file path, should end with .mp4 (or .aac on Windows 8) + Desired bitrate. Use GetEncodeBitrates to find the possibilities for your input type + + + + Tries to find the encoding media type with the closest bitrate to that specified + + Audio subtype, a value from AudioSubtypes + Your encoder input format (used to check sample rate and channel count) + Your desired bitrate + The closest media type, or null if none available + + + + Creates a new encoder that encodes to the specified output media type + + Desired output media type + + + + Encodes a file + + Output filename (container type is deduced from the filename) + Input provider (should be PCM, some encoders will also allow IEEE float) + + + + Disposes this instance + + + + + + Disposes this instance + + + + + Finalizer + + + + + Stopped Event Args + + + + + Initializes a new instance of StoppedEventArgs + + An exception to report (null if no exception) + + + + An exception. Will be null if the playback or record operation stopped + + + + + IWaveBuffer interface use to store wave datas. + Data can be manipulated with arrays (,, + , ) that are pointing to the same memory buffer. + This is a requirement for all subclasses. + + Use the associated Count property based on the type of buffer to get the number of data in the + buffer. + + for the standard implementation using C# unions. + + + + + Gets the byte buffer. + + The byte buffer. + + + + Gets the float buffer. + + The float buffer. + + + + Gets the short buffer. + + The short buffer. + + + + Gets the int buffer. + + The int buffer. + + + + Gets the max size in bytes of the byte buffer.. + + Maximum number of bytes in the buffer. + + + + Gets the byte buffer count. + + The byte buffer count. + + + + Gets the float buffer count. + + The float buffer count. + + + + Gets the short buffer count. + + The short buffer count. + + + + Gets the int buffer count. + + The int buffer count. + + + + Represents the interface to a device that can play a WaveFile + + + + + Begin playback + + + + + Stop playback + + + + + Pause Playback + + + + + Initialise playback + + The waveprovider to be played + + + + Current playback state + + + + + The volume 1.0 is full scale + + + + + Indicates that playback has gone into a stopped state due to + reaching the end of the input stream or an error has been encountered during playback + + + + + Interface for IWavePlayers that can report position + + + + + Position (in terms of bytes played - does not necessarily) + + Position in bytes + + + + Gets a instance indicating the format the hardware is using. + + + + + Generic interface for all WaveProviders. + + + + + Gets the WaveFormat of this WaveProvider. + + The wave format. + + + + Fill the specified buffer with wave data. + + The buffer to fill of wave data. + Offset into buffer + The number of bytes to read + the number of bytes written to the buffer. + + + + NativeDirectSoundOut using DirectSound COM interop. + Contact author: Alexandre Mutel - alexandre_mutel at yahoo.fr + Modified by: Graham "Gee" Plumb + + + + + Playback Stopped + + + + + Gets the DirectSound output devices in the system + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class. + (40ms seems to work under Vista). + + The latency. + Selected device + + + + Releases unmanaged resources and performs other cleanup operations before the + is reclaimed by garbage collection. + + + + + Begin playback + + + + + Stop playback + + + + + Pause Playback + + + + + Gets the current position in bytes from the wave output device. + (n.b. this is not the same thing as the position within your reader + stream) + + Position in bytes + + + + Gets the current position from the wave output device. + + + + + Initialise playback + + The waveprovider to be played + + + + Current playback state + + + + + + The volume 1.0 is full scale + + + + + + Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + + + + + Determines whether the SecondaryBuffer is lost. + + + true if [is buffer lost]; otherwise, false. + + + + + Convert ms to bytes size according to WaveFormat + + The ms + number of byttes + + + + Processes the samples in a separate thread. + + + + + Stop playback + + + + + Feeds the SecondaryBuffer with the WaveStream + + number of bytes to feed + + + + IDirectSound interface + + + + + IDirectSoundBuffer interface + + + + + IDirectSoundNotify interface + + + + + Instanciate DirectSound from the DLL + + The GUID. + The direct sound. + The p unk outer. + + + + DirectSound default playback device GUID + + + + + DirectSound default capture device GUID + + + + + DirectSound default device for voice playback + + + + + DirectSound default device for voice capture + + + + + The DSEnumCallback function is an application-defined callback function that enumerates the DirectSound drivers. + The system calls this function in response to the application's call to the DirectSoundEnumerate or DirectSoundCaptureEnumerate function. + + Address of the GUID that identifies the device being enumerated, or NULL for the primary device. This value can be passed to the DirectSoundCreate8 or DirectSoundCaptureCreate8 function to create a device object for that driver. + Address of a null-terminated string that provides a textual description of the DirectSound device. + Address of a null-terminated string that specifies the module name of the DirectSound driver corresponding to this device. + Address of application-defined data. This is the pointer passed to DirectSoundEnumerate or DirectSoundCaptureEnumerate as the lpContext parameter. + Returns TRUE to continue enumerating drivers, or FALSE to stop. + + + + The DirectSoundEnumerate function enumerates the DirectSound drivers installed in the system. + + callback function + User context + + + + Gets the HANDLE of the desktop window. + + HANDLE of the Desktop window + + + + Class for enumerating DirectSound devices + + + + + The device identifier + + + + + Device description + + + + + Device module name + + + + + Like IWaveProvider, but makes it much simpler to put together a 32 bit floating + point mixing engine + + + + + Gets the WaveFormat of this Sample Provider. + + The wave format. + + + + Fill the specified buffer with 32 bit floating point samples + + The buffer to fill with samples. + Offset into buffer + The number of samples to read + the number of samples written to the buffer. + + + + Playback State + + + + + Stopped + + + + + Playing + + + + + Paused + + + + + Support for playback using Wasapi + + + + + Playback Stopped + + + + + WASAPI Out shared mode, defauult + + + + + WASAPI Out using default audio endpoint + + ShareMode - shared or exclusive + Desired latency in milliseconds + + + + WASAPI Out using default audio endpoint + + ShareMode - shared or exclusive + true if sync is done with event. false use sleep. + Desired latency in milliseconds + + + + Creates a new WASAPI Output + + Device to use + + true if sync is done with event. false use sleep. + Desired latency in milliseconds + + + + Gets the current position in bytes from the wave output device. + (n.b. this is not the same thing as the position within your reader + stream) + + Position in bytes + + + + Gets a instance indicating the format the hardware is using. + + + + + Begin Playback + + + + + Stop playback and flush buffers + + + + + Stop playback without flushing buffers + + + + + Initialize for playing the specified wave stream + + IWaveProvider to play + + + + Playback State + + + + + Volume + + + + + Retrieve the AudioStreamVolume object for this audio stream + + + This returns the AudioStreamVolume object ONLY for shared audio streams. + + + This is thrown when an exclusive audio stream is being used. + + + + + Dispose + + + + + WaveBuffer class use to store wave datas. Data can be manipulated with arrays + (,,, ) that are pointing to the + same memory buffer. Use the associated Count property based on the type of buffer to get the number of + data in the buffer. + Implicit casting is now supported to float[], byte[], int[], short[]. + You must not use Length on returned arrays. + + n.b. FieldOffset is 8 now to allow it to work natively on 64 bit + + + + + Number of Bytes + + + + + Initializes a new instance of the class. + + The number of bytes. The size of the final buffer will be aligned on 4 Bytes (upper bound) + + + + Initializes a new instance of the class binded to a specific byte buffer. + + A byte buffer to bound the WaveBuffer to. + + + + Binds this WaveBuffer instance to a specific byte buffer. + + A byte buffer to bound the WaveBuffer to. + + + + Performs an implicit conversion from to . + + The wave buffer. + The result of the conversion. + + + + Performs an implicit conversion from to . + + The wave buffer. + The result of the conversion. + + + + Performs an implicit conversion from to . + + The wave buffer. + The result of the conversion. + + + + Performs an implicit conversion from to . + + The wave buffer. + The result of the conversion. + + + + Gets the byte buffer. + + The byte buffer. + + + + Gets the float buffer. + + The float buffer. + + + + Gets the short buffer. + + The short buffer. + + + + Gets the int buffer. + + The int buffer. + + + + Gets the max size in bytes of the byte buffer.. + + Maximum number of bytes in the buffer. + + + + Gets or sets the byte buffer count. + + The byte buffer count. + + + + Gets or sets the float buffer count. + + The float buffer count. + + + + Gets or sets the short buffer count. + + The short buffer count. + + + + Gets or sets the int buffer count. + + The int buffer count. + + + + Clears the associated buffer. + + + + + Copy this WaveBuffer to a destination buffer up to ByteBufferCount bytes. + + + + + Checks the validity of the count parameters. + + Name of the arg. + The value. + The size of value. + + + + Wave Callback Info + + + + + Callback Strategy + + + + + Window Handle (if applicable) + + + + + Sets up a new WaveCallbackInfo for function callbacks + + + + + Sets up a new WaveCallbackInfo to use a New Window + IMPORTANT: only use this on the GUI thread + + + + + Sets up a new WaveCallbackInfo to use an existing window + IMPORTANT: only use this on the GUI thread + + + + + Wave Callback Strategy + + + + + Use a function + + + + + Create a new window (should only be done if on GUI thread) + + + + + Use an existing window handle + + + + + Use an event handle + + + + + This class writes WAV data to a .wav file on disk + + + + + Creates a 16 bit Wave File from an ISampleProvider + BEWARE: the source provider must not return data indefinitely + + The filename to write to + The source sample provider + + + + Creates a Wave file by reading all the data from a WaveProvider + BEWARE: the WaveProvider MUST return 0 from its Read method when it is finished, + or the Wave File will grow indefinitely. + + The filename to use + The source WaveProvider + + + + Writes to a stream by reading all the data from a WaveProvider + BEWARE: the WaveProvider MUST return 0 from its Read method when it is finished, + or the Wave File will grow indefinitely. + + The stream the method will output to + The source WaveProvider + + + + WaveFileWriter that actually writes to a stream + + Stream to be written to + Wave format to use + + + + Creates a new WaveFileWriter + + The filename to write to + The Wave Format of the output data + + + + The wave file name or null if not applicable + + + + + Number of bytes of audio in the data chunk + + + + + WaveFormat of this wave file + + + + + Returns false: Cannot read from a WaveFileWriter + + + + + Returns true: Can write to a WaveFileWriter + + + + + Returns false: Cannot seek within a WaveFileWriter + + + + + Read is not supported for a WaveFileWriter + + + + + Seek is not supported for a WaveFileWriter + + + + + SetLength is not supported for WaveFileWriter + + + + + + Gets the Position in the WaveFile (i.e. number of bytes written so far) + + + + + Appends bytes to the WaveFile (assumes they are already in the correct format) + + the buffer containing the wave data + the offset from which to start writing + the number of bytes to write + + + + Appends bytes to the WaveFile (assumes they are already in the correct format) + + the buffer containing the wave data + the offset from which to start writing + the number of bytes to write + + + + Writes a single sample to the Wave file + + the sample to write (assumed floating point with 1.0f as max value) + + + + Writes 32 bit floating point samples to the Wave file + They will be converted to the appropriate bit depth depending on the WaveFormat of the WAV file + + The buffer containing the floating point samples + The offset from which to start writing + The number of floating point samples to write + + + + Writes 16 bit samples to the Wave file + + The buffer containing the 16 bit samples + The offset from which to start writing + The number of 16 bit samples to write + + + + Writes 16 bit samples to the Wave file + + The buffer containing the 16 bit samples + The offset from which to start writing + The number of 16 bit samples to write + + + + Ensures data is written to disk + Also updates header, so that WAV file will be valid up to the point currently written + + + + + Actually performs the close,making sure the header contains the correct data + + True if called from Dispose + + + + Updates the header with file size information + + + + + Finaliser - should only be called if the user forgot to close this WaveFileWriter + + + + + Represents a wave out device + + + + + Indicates playback has stopped automatically + + + + + Retrieves the capabilities of a waveOut device + + Device to test + The WaveOut device capabilities + + + + Returns the number of Wave Out devices available in the system + + + + + Gets or sets the desired latency in milliseconds + Should be set before a call to Init + + + + + Gets or sets the number of buffers used + Should be set before a call to Init + + + + + Gets or sets the device number + Should be set before a call to Init + This must be between 0 and DeviceCount - 1. + + + + + Creates a default WaveOut device + Will use window callbacks if called from a GUI thread, otherwise function + callbacks + + + + + Creates a WaveOut device using the specified window handle for callbacks + + A valid window handle + + + + Opens a WaveOut device + + + + + Initialises the WaveOut device + + WaveProvider to play + + + + Start playing the audio from the WaveStream + + + + + Pause the audio + + + + + Resume playing after a pause from the same position + + + + + Stop and reset the WaveOut device + + + + + Gets the current position in bytes from the wave output device. + (n.b. this is not the same thing as the position within your reader + stream - it calls directly into waveOutGetPosition) + + Position in bytes + + + + Gets a instance indicating the format the hardware is using. + + + + + Playback State + + + + + Volume for this device 1.0 is full scale + + + + + Closes this WaveOut device + + + + + Closes the WaveOut device and disposes of buffers + + True if called from Dispose + + + + Finalizer. Only called when user forgets to call Dispose + + + + + Alternative WaveOut class, making use of the Event callback + + + + + Indicates playback has stopped automatically + + + + + Gets or sets the desired latency in milliseconds + Should be set before a call to Init + + + + + Gets or sets the number of buffers used + Should be set before a call to Init + + + + + Gets or sets the device number + Should be set before a call to Init + This must be between 0 and DeviceCount - 1. + + + + + Opens a WaveOut device + + + + + Initialises the WaveOut device + + WaveProvider to play + + + + Start playing the audio from the WaveStream + + + + + Pause the audio + + + + + Resume playing after a pause from the same position + + + + + Stop and reset the WaveOut device + + + + + Gets the current position in bytes from the wave output device. + (n.b. this is not the same thing as the position within your reader + stream - it calls directly into waveOutGetPosition) + + Position in bytes + + + + Gets a instance indicating the format the hardware is using. + + + + + Playback State + + + + + Obsolete property + + + + + Closes this WaveOut device + + + + + Closes the WaveOut device and disposes of buffers + + True if called from Dispose + + + + Finalizer. Only called when user forgets to call Dispose + + + + + Provides a buffered store of samples + Read method will return queued samples or fill buffer with zeroes + Now backed by a circular buffer + + + + + Creates a new buffered WaveProvider + + WaveFormat + + + + If true, always read the amount of data requested, padding with zeroes if necessary + By default is set to true + + + + + Buffer length in bytes + + + + + Buffer duration + + + + + If true, when the buffer is full, start throwing away data + if false, AddSamples will throw an exception when buffer is full + + + + + The number of buffered bytes + + + + + Buffered Duration + + + + + Gets the WaveFormat + + + + + Adds samples. Takes a copy of buffer, so that buffer can be reused if necessary + + + + + Reads from this WaveProvider + Will always return count bytes, since we will zero-fill the buffer if not enough available + + + + + Discards all audio from the buffer + + + + + The Media Foundation Resampler Transform + + + + + Creates the Media Foundation Resampler, allowing modifying of sample rate, bit depth and channel count + + Source provider, must be PCM + Output format, must also be PCM + + + + Creates a resampler with a specified target output sample rate + + Source provider + Output sample rate + + + + Creates and configures the actual Resampler transform + + A newly created and configured resampler MFT + + + + Gets or sets the Resampler quality. n.b. set the quality before starting to resample. + 1 is lowest quality (linear interpolation) and 60 is best quality + + + + + Disposes this resampler + + + + + WaveProvider that can mix together multiple 32 bit floating point input provider + All channels must have the same number of inputs and same sample rate + n.b. Work in Progress - not tested yet + + + + + Creates a new MixingWaveProvider32 + + + + + Creates a new 32 bit MixingWaveProvider32 + + inputs - must all have the same format. + Thrown if the input streams are not 32 bit floating point, + or if they have different formats to each other + + + + Add a new input to the mixer + + The wave input to add + + + + Remove an input from the mixer + + waveProvider to remove + + + + The number of inputs to this mixer + + + + + Reads bytes from this wave stream + + buffer to read into + offset into buffer + number of bytes required + Number of bytes read. + Thrown if an invalid number of bytes requested + + + + Actually performs the mixing + + + + + + + + + + Allows any number of inputs to be patched to outputs + Uses could include swapping left and right channels, turning mono into stereo, + feeding different input sources to different soundcard outputs etc + + + + + Creates a multiplexing wave provider, allowing re-patching of input channels to different + output channels + + Input wave providers. Must all be of the same format, but can have any number of channels + Desired number of output channels. + + + + persistent temporary buffer to prevent creating work for garbage collector + + + + + Reads data from this WaveProvider + + Buffer to be filled with sample data + Offset to write to within buffer, usually 0 + Number of bytes required + Number of bytes read + + + + The WaveFormat of this WaveProvider + + + + + Connects a specified input channel to an output channel + + Input Channel index (zero based). Must be less than InputChannelCount + Output Channel index (zero based). Must be less than OutputChannelCount + + + + The number of input channels. Note that this is not the same as the number of input wave providers. If you pass in + one stereo and one mono input provider, the number of input channels is three. + + + + + The number of output channels, as specified in the constructor. + + + + + Silence producing wave provider + Useful for playing silence when doing a WASAPI Loopback Capture + + + + + Creates a new silence producing wave provider + + Desired WaveFormat (should be PCM / IEE float + + + + Read silence from into the buffer + + + + + WaveFormat of this silence producing wave provider + + + + + Takes a stereo 16 bit input and turns it mono, allowing you to select left or right channel only or mix them together + + + + + Creates a new mono waveprovider based on a stereo input + + Stereo 16 bit PCM input + + + + 1.0 to mix the mono source entirely to the left channel + + + + + 1.0 to mix the mono source entirely to the right channel + + + + + Output Wave Format + + + + + Reads bytes from this WaveProvider + + + + + Converts from mono to stereo, allowing freedom to route all, some, or none of the incoming signal to left or right channels + + + + + Creates a new stereo waveprovider based on a mono input + + Mono 16 bit PCM input + + + + 1.0 to copy the mono stream to the left channel without adjusting volume + + + + + 1.0 to copy the mono stream to the right channel without adjusting volume + + + + + Output Wave Format + + + + + Reads bytes from this WaveProvider + + + + + Helper class allowing us to modify the volume of a 16 bit stream without converting to IEEE float + + + + + Constructs a new VolumeWaveProvider16 + + Source provider, must be 16 bit PCM + + + + Gets or sets volume. + 1.0 is full scale, 0.0 is silence, anything over 1.0 will amplify but potentially clip + + + + + WaveFormat of this WaveProvider + + + + + Read bytes from this WaveProvider + + Buffer to read into + Offset within buffer to read to + Bytes desired + Bytes read + + + + Converts IEEE float to 16 bit PCM, optionally clipping and adjusting volume along the way + + + + + Creates a new WaveFloatTo16Provider + + the source provider + + + + Reads bytes from this wave stream + + The destination buffer + Offset into the destination buffer + Number of bytes read + Number of bytes read. + + + + + + + + + Volume of this channel. 1.0 = full scale + + + + + Converts 16 bit PCM to IEEE float, optionally adjusting volume along the way + + + + + Creates a new Wave16toFloatProvider + + the source provider + + + + Reads bytes from this wave stream + + The destination buffer + Offset into the destination buffer + Number of bytes read + Number of bytes read. + + + + + + + + + Volume of this channel. 1.0 = full scale + + + + + Buffered WaveProvider taking source data from WaveIn + + + + + Creates a new WaveInProvider + n.b. Should make sure the WaveFormat is set correctly on IWaveIn before calling + + The source of wave data + + + + Reads data from the WaveInProvider + + + + + The WaveFormat + + + + + Base class for creating a 16 bit wave provider + + + + + Initializes a new instance of the WaveProvider16 class + defaulting to 44.1kHz mono + + + + + Initializes a new instance of the WaveProvider16 class with the specified + sample rate and number of channels + + + + + Allows you to specify the sample rate and channels for this WaveProvider + (should be initialised before you pass it to a wave player) + + + + + Implements the Read method of IWaveProvider by delegating to the abstract + Read method taking a short array + + + + + Method to override in derived classes + Supply the requested number of samples into the buffer + + + + + The Wave Format + + + + + Base class for creating a 32 bit floating point wave provider + Can also be used as a base class for an ISampleProvider that can + be plugged straight into anything requiring an IWaveProvider + + + + + Initializes a new instance of the WaveProvider32 class + defaulting to 44.1kHz mono + + + + + Initializes a new instance of the WaveProvider32 class with the specified + sample rate and number of channels + + + + + Allows you to specify the sample rate and channels for this WaveProvider + (should be initialised before you pass it to a wave player) + + + + + Implements the Read method of IWaveProvider by delegating to the abstract + Read method taking a float array + + + + + Method to override in derived classes + Supply the requested number of samples into the buffer + + + + + The Wave Format + + + + + Utility class to intercept audio from an IWaveProvider and + save it to disk + + + + + Constructs a new WaveRecorder + + The location to write the WAV file to + The Source Wave Provider + + + + Read simply returns what the source returns, but writes to disk along the way + + + + + The WaveFormat + + + + + Closes the WAV file + + + + A read-only stream of AIFF data based on an aiff file + with an associated WaveFormat + originally contributed to NAudio by Giawa + + + + Supports opening a AIF file + The AIF is of similar nastiness to the WAV format. + This supports basic reading of uncompressed PCM AIF files, + with 8, 16, 24 and 32 bit PCM data. + + + + + Creates an Aiff File Reader based on an input stream + + The input stream containing a AIF file including header + + + + Ensures valid AIFF header and then finds data offset. + + The stream, positioned at the start of audio data + The format found + The position of the data chunk + The length of the data chunk + Additional chunks found + + + + Cleans up the resources associated with this AiffFileReader + + + + + + + + + + + + + + + Number of Samples (if possible to calculate) + + + + + Position in the AIFF file + + + + + + Reads bytes from the AIFF File + + + + + + AIFF Chunk + + + + + Chunk Name + + + + + Chunk Length + + + + + Chunk start + + + + + Creates a new AIFF Chunk + + + + + AudioFileReader simplifies opening an audio file in NAudio + Simply pass in the filename, and it will attempt to open the + file and set up a conversion path that turns into PCM IEEE float. + ACM codecs will be used for conversion. + It provides a volume property and implements both WaveStream and + ISampleProvider, making it possibly the only stage in your audio + pipeline necessary for simple playback scenarios + + + + + Initializes a new instance of AudioFileReader + + The file to open + + + + Creates the reader stream, supporting all filetypes in the core NAudio library, + and ensuring we are in PCM format + + File Name + + + + WaveFormat of this stream + + + + + Length of this stream (in bytes) + + + + + Position of this stream (in bytes) + + + + + Reads from this wave stream + + Audio buffer + Offset into buffer + Number of bytes required + Number of bytes read + + + + Reads audio from this sample provider + + Sample buffer + Offset into sample buffer + Number of samples required + Number of samples read + + + + Gets or Sets the Volume of this AudioFileReader. 1.0f is full volume + + + + + Helper to convert source to dest bytes + + + + + Helper to convert dest to source bytes + + + + + Disposes this AudioFileReader + + True if called from Dispose + + + + Helper stream that lets us read from compressed audio files with large block alignment + as though we could read any amount and reposition anywhere + + + + + Creates a new BlockAlignReductionStream + + the input stream + + + + Block alignment of this stream + + + + + Wave Format + + + + + Length of this Stream + + + + + Current position within stream + + + + + Disposes this WaveStream + + + + + Reads data from this stream + + + + + + + + + Implementation of Com IStream + + + + + Holds information on a cue: a labeled position within a Wave file + + + + + Cue position in samples + + + + + Label of the cue + + + + + Creates a Cue based on a sample position and label + + + + + + + Holds a list of cues + + + The specs for reading and writing cues from the cue and list RIFF chunks + are from http://www.sonicspot.com/guide/wavefiles.html and http://www.wotsit.org/ + ------------------------------ + The cues are stored like this: + ------------------------------ + struct CuePoint + { + Int32 dwIdentifier; + Int32 dwPosition; + Int32 fccChunk; + Int32 dwChunkStart; + Int32 dwBlockStart; + Int32 dwSampleOffset; + } + + struct CueChunk + { + Int32 chunkID; + Int32 chunkSize; + Int32 dwCuePoints; + CuePoint[] points; + } + ------------------------------ + Labels look like this: + ------------------------------ + struct ListHeader + { + Int32 listID; /* 'list' */ + Int32 chunkSize; /* includes the Type ID below */ + Int32 typeID; /* 'adtl' */ + } + + struct LabelChunk + { + Int32 chunkID; + Int32 chunkSize; + Int32 dwIdentifier; + Char[] dwText; /* Encoded with extended ASCII */ + } LabelChunk; + + + + + Creates an empty cue list + + + + + Adds an item to the list + + Cue + + + + Gets sample positions for the embedded cues + + Array containing the cue positions + + + + Gets labels for the embedded cues + + Array containing the labels + + + + Creates a cue list from the cue RIFF chunk and the list RIFF chunk + + The data contained in the cue chunk + The data contained in the list chunk + + + + Gets the cues as the concatenated cue and list RIFF chunks. + + RIFF chunks containing the cue data + + + + Number of cues + + + + + Accesses the cue at the specified index + + + + + + + Checks if the cue and list chunks exist and if so, creates a cue list + + + + + A wave file reader supporting cue reading + + + + + Loads a wavefile and supports reading cues + + + + + + Cue List (can be null if cues not present) + + + + + An interface for WaveStreams which can report notification of individual samples + + + + + A sample has been detected + + + + + Sample event arguments + + + + + Left sample + + + + + Right sample + + + + + Constructor + + + + + Class for reading any file that Media Foundation can play + Will only work in Windows Vista and above + Automatically converts to PCM + If it is a video file with multiple audio streams, it will pick out the first audio stream + + + + + Allows customisation of this reader class + + + + + Sets up the default settings for MediaFoundationReader + + + + + Allows us to request IEEE float output (n.b. no guarantee this will be accepted) + + + + + If true, the reader object created in the constructor is used in Read + Should only be set to true if you are working entirely on an STA thread, or + entirely with MTA threads. + + + + + If true, the reposition does not happen immediately, but waits until the + next call to read to be processed. + + + + + Default constructor + + + + + Creates a new MediaFoundationReader based on the supplied file + + Filename (can also be a URL e.g. http:// mms:// file://) + + + + Creates a new MediaFoundationReader based on the supplied file + + Filename + Advanced settings + + + + Initializes + + + + + Creates the reader (overridable by ) + + + + + Reads from this wave stream + + Buffer to read into + Offset in buffer + Bytes required + Number of bytes read; 0 indicates end of stream + + + + WaveFormat of this stream (n.b. this is after converting to PCM) + + + + + The bytesRequired of this stream in bytes (n.b may not be accurate) + + + + + Current position within this stream + + + + + Cleans up after finishing with this reader + + true if called from Dispose + + + + WaveFormat has changed + + + + + Class for reading from MP3 files + + + + + The MP3 wave format (n.b. NOT the output format of this stream - see the WaveFormat property) + + + + Supports opening a MP3 file + + + Supports opening a MP3 file + MP3 File name + Factory method to build a frame decompressor + + + + Opens MP3 from a stream rather than a file + Will not dispose of this stream itself + + The incoming stream containing MP3 data + + + + Opens MP3 from a stream rather than a file + Will not dispose of this stream itself + + The incoming stream containing MP3 data + Factory method to build a frame decompressor + + + + Function that can create an MP3 Frame decompressor + + A WaveFormat object describing the MP3 file format + An MP3 Frame decompressor + + + + Creates an ACM MP3 Frame decompressor. This is the default with NAudio + + A WaveFormat object based + + + + + Gets the total length of this file in milliseconds. + + + + + ID3v2 tag if present + + + + + ID3v1 tag if present + + + + + Reads the next mp3 frame + + Next mp3 frame, or null if EOF + + + + Reads the next mp3 frame + + Next mp3 frame, or null if EOF + + + + This is the length in bytes of data available to be read out from the Read method + (i.e. the decompressed MP3 length) + n.b. this may return 0 for files whose length is unknown + + + + + + + + + + + + + + + Reads decompressed PCM data from our MP3 file. + + + + + Xing header if present + + + + + Disposes this WaveStream + + + + + WaveStream that simply passes on data from its source stream + (e.g. a MemoryStream) + + + + + Initialises a new instance of RawSourceWaveStream + + The source stream containing raw audio + The waveformat of the audio in the source stream + + + + Initialises a new instance of RawSourceWaveStream + + The buffer containing raw audio + Offset in the source buffer to read from + Number of bytes to read in the buffer + The waveformat of the audio in the source stream + + + + The WaveFormat of this stream + + + + + The length in bytes of this stream (if supported) + + + + + The current position in this stream + + + + + Reads data from the stream + + + + + Wave Stream for converting between sample rates + + + + + WaveStream to resample using the DMO Resampler + + Input Stream + Desired Output Format + + + + Stream Wave Format + + + + + Stream length in bytes + + + + + Stream position in bytes + + + + + Reads data from input stream + + buffer + offset into buffer + Bytes required + Number of bytes read + + + + Dispose + + True if disposing (not from finalizer) + + + + Holds information about a RIFF file chunk + + + + + Creates a RiffChunk object + + + + + The chunk identifier + + + + + The chunk identifier converted to a string + + + + + The chunk length + + + + + The stream position this chunk is located at + + + + + A simple compressor + + + + + Create a new simple compressor stream + + Source stream + + + + Make-up Gain + + + + + Threshold + + + + + Ratio + + + + + Attack time + + + + + Release time + + + + + Determine whether the stream has the required amount of data. + + Number of bytes of data required from the stream. + Flag indicating whether the required amount of data is avialable. + + + + Turns gain on or off + + + + + Returns the stream length + + + + + Gets or sets the current position in the stream + + + + + Gets the WaveFormat of this stream + + + + + Reads bytes from this stream + + Buffer to read into + Offset in array to read into + Number of bytes to read + Number of bytes read + + + + Disposes this stream + + true if the user called this + + + + Gets the block alignment for this stream + + + + + MediaFoundationReader supporting reading from a stream + + + + + Constructs a new media foundation reader from a stream + + + + + Creates the reader + + + + + WaveStream that converts 32 bit audio back down to 16 bit, clipping if necessary + + + + + The method reuses the same buffer to prevent + unnecessary allocations. + + + + + Creates a new Wave32To16Stream + + the source stream + + + + Sets the volume for this stream. 1.0f is full scale + + + + + + + + + + Returns the stream length + + + + + Gets or sets the current position in the stream + + + + + Reads bytes from this wave stream + + Destination buffer + Offset into destination buffer + + Number of bytes read. + + + + Conversion to 16 bit and clipping + + + + + + + + + + Clip indicator. Can be reset. + + + + + Disposes this WaveStream + + + + + Represents Channel for the WaveMixerStream + 32 bit output and 16 bit input + It's output is always stereo + The input stream can be panned + + + + + Creates a new WaveChannel32 + + the source stream + stream volume (1 is 0dB) + pan control (-1 to 1) + + + + Creates a WaveChannel32 with default settings + + The source stream + + + + Gets the block alignment for this WaveStream + + + + + Returns the stream length + + + + + Gets or sets the current position in the stream + + + + + Reads bytes from this wave stream + + The destination buffer + Offset into the destination buffer + Number of bytes read + Number of bytes read. + + + + If true, Read always returns the number of bytes requested + + + + + + + + + + Volume of this channel. 1.0 = full scale + + + + + Pan of this channel (from -1 to 1) + + + + + Determines whether this channel has any data to play + to allow optimisation to not read, but bump position forward + + + + + Disposes this WaveStream + + + + + Sample + + + + + Raise the sample event (no check for null because it has already been done) + + + + This class supports the reading of WAV files, + providing a repositionable WaveStream that returns the raw data + contained in the WAV file + + + + Supports opening a WAV file + The WAV file format is a real mess, but we will only + support the basic WAV file format which actually covers the vast + majority of WAV files out there. For more WAV file format information + visit www.wotsit.org. If you have a WAV file that can't be read by + this class, email it to the NAudio project and we will probably + fix this reader to support it + + + + + Creates a Wave File Reader based on an input stream + + The input stream containing a WAV file including header + + + + Gets a list of the additional chunks found in this file + + + + + Gets the data for the specified chunk + + + + + Cleans up the resources associated with this WaveFileReader + + + + + + + + + + This is the length of audio data contained in this WAV file, in bytes + (i.e. the byte length of the data chunk, not the length of the WAV file itself) + + + + + + Number of Sample Frames (if possible to calculate) + This currently does not take into account number of channels + Multiply number of channels if you want the total number of samples + + + + + Position in the WAV data chunk. + + + + + + Reads bytes from the Wave File + + + + + + Attempts to read the next sample or group of samples as floating point normalised into the range -1.0f to 1.0f + + An array of samples, 1 for mono, 2 for stereo etc. Null indicates end of file reached + + + + + Attempts to read a sample into a float. n.b. only applicable for uncompressed formats + Will normalise the value read into the range -1.0f to 1.0f if it comes from a PCM encoding + + False if the end of the WAV data chunk was reached + + + + IWaveProvider that passes through an ACM Codec + + + + + Create a new WaveFormat conversion stream + + Desired output format + Source Provider + + + + Gets the WaveFormat of this stream + + + + + Indicates that a reposition has taken place, and internal buffers should be reset + + + + + Reads bytes from this stream + + Buffer to read into + Offset in buffer to read into + Number of bytes to read + Number of bytes read + + + + Disposes this stream + + true if the user called this + + + + Disposes this resource + + + + + Finalizer + + + + + WaveStream that passes through an ACM Codec + + + + + Create a new WaveFormat conversion stream + + Desired output format + Source stream + + + + Creates a stream that can convert to PCM + + The source stream + A PCM stream + + + + Gets or sets the current position in the stream + + + + + Converts source bytes to destination bytes + + + + + Converts destination bytes to source bytes + + + + + Returns the stream length + + + + + Gets the WaveFormat of this stream + + + + + + + Buffer to read into + Offset within buffer to write to + Number of bytes to read + Bytes read + + + + Disposes this stream + + true if the user called this + + + + A buffer of Wave samples + + + + + creates a new wavebuffer + + WaveIn device to write to + Buffer size in bytes + + + + Place this buffer back to record more audio + + + + + Finalizer for this wave buffer + + + + + Releases resources held by this WaveBuffer + + + + + Releases resources held by this WaveBuffer + + + + + Provides access to the actual record buffer (for reading only) + + + + + Indicates whether the Done flag is set on this buffer + + + + + Indicates whether the InQueue flag is set on this buffer + + + + + Number of bytes recorded + + + + + The buffer size in bytes + + + + + WaveStream that can mix together multiple 32 bit input streams + (Normally used with stereo input channels) + All channels must have the same number of inputs + + + + + Creates a new 32 bit WaveMixerStream + + + + + Creates a new 32 bit WaveMixerStream + + An Array of WaveStreams - must all have the same format. + Use WaveChannel is designed for this purpose. + Automatically stop when all inputs have been read + Thrown if the input streams are not 32 bit floating point, + or if they have different formats to each other + + + + Add a new input to the mixer + + The wave input to add + + + + Remove a WaveStream from the mixer + + waveStream to remove + + + + The number of inputs to this mixer + + + + + Automatically stop when all inputs have been read + + + + + Reads bytes from this wave stream + + buffer to read into + offset into buffer + number of bytes required + Number of bytes read. + Thrown if an invalid number of bytes requested + + + + Actually performs the mixing + + + + + + + + + + Length of this Wave Stream (in bytes) + + + + + + Position within this Wave Stream (in bytes) + + + + + + + + + + + Disposes this WaveStream + + + + + Simply shifts the input stream in time, optionally + clipping its start and end. + (n.b. may include looping in the future) + + + + + Creates a new WaveOffsetStream + + the source stream + the time at which we should start reading from the source stream + amount to trim off the front of the source stream + length of time to play from source stream + + + + Creates a WaveOffsetStream with default settings (no offset or pre-delay, + and whole length of source stream) + + The source stream + + + + The length of time before which no audio will be played + + + + + An offset into the source stream from which to start playing + + + + + Length of time to read from the source stream + + + + + Gets the block alignment for this WaveStream + + + + + Returns the stream length + + + + + Gets or sets the current position in the stream + + + + + Reads bytes from this wave stream + + The destination buffer + Offset into the destination buffer + Number of bytes read + Number of bytes read. + + + + + + + + + Determines whether this channel has any data to play + to allow optimisation to not read, but bump position forward + + + + + Disposes this WaveStream + + + + + A buffer of Wave samples for streaming to a Wave Output device + + + + + creates a new wavebuffer + + WaveOut device to write to + Buffer size in bytes + Stream to provide more data + Lock to protect WaveOut API's from being called on >1 thread + + + + Finalizer for this wave buffer + + + + + Releases resources held by this WaveBuffer + + + + + Releases resources held by this WaveBuffer + + + + this is called by the WAVE callback and should be used to refill the buffer + + + + Whether the header's in queue flag is set + + + + + The buffer size in bytes + + + + + Base class for all WaveStream classes. Derives from stream. + + + + + Retrieves the WaveFormat for this stream + + + + + We can read from this stream + + + + + We can seek within this stream + + + + + We can't write to this stream + + + + + Flush does not need to do anything + See + + + + + An alternative way of repositioning. + See + + + + + Sets the length of the WaveStream. Not Supported. + + + + + + Writes to the WaveStream. Not Supported. + + + + + The block alignment for this wavestream. Do not modify the Position + to anything that is not a whole multiple of this value + + + + + Moves forward or backwards the specified number of seconds in the stream + + Number of seconds to move, can be negative + + + + The current position in the stream in Time format + + + + + Total length in real-time of the stream (may be an estimate for compressed files) + + + + + Whether the WaveStream has non-zero sample data at the current position for the + specified count + + Number of bytes to read + + + + Contains the name and CLSID of a DirectX Media Object + + + + + Name + + + + + Clsid + + + + + Initializes a new instance of DmoDescriptor + + + + + DirectX Media Object Enumerator + + + + + Get audio effect names + + Audio effect names + + + + Get audio encoder names + + Audio encoder names + + + + Get audio decoder names + + Audio decoder names + + + + DMO Guids for use with DMOEnum + dmoreg.h + + + + + MediaErr.h + + + + + DMO_PARTIAL_MEDIATYPE + + + + + defined in Medparam.h + + + + + Windows Media Resampler Props + wmcodecdsp.h + + + + + Range is 1 to 60 + + + + + Specifies the channel matrix. + + + + + Attempting to implement the COM IMediaBuffer interface as a .NET object + Not sure what will happen when I pass this to an unmanaged object + + + + + Creates a new Media Buffer + + Maximum length in bytes + + + + Dispose and free memory for buffer + + + + + Finalizer + + + + + Set length of valid data in the buffer + + length + HRESULT + + + + Gets the maximum length of the buffer + + Max length (output parameter) + HRESULT + + + + Gets buffer and / or length + + Pointer to variable into which buffer pointer should be written + Pointer to variable into which valid data length should be written + HRESULT + + + + Length of data in the media buffer + + + + + Loads data into this buffer + + Data to load + Number of bytes to load + + + + Retrieves the data in the output buffer + + buffer to retrieve into + offset within that buffer + + + + Media Object + + + + + Creates a new Media Object + + Media Object COM interface + + + + Number of input streams + + + + + Number of output streams + + + + + Gets the input media type for the specified input stream + + Input stream index + Input type index + DMO Media Type or null if there are no more input types + + + + Gets the DMO Media Output type + + The output stream + Output type index + DMO Media Type or null if no more available + + + + retrieves the media type that was set for an output stream, if any + + Output stream index + DMO Media Type or null if no more available + + + + Enumerates the supported input types + + Input stream index + Enumeration of input types + + + + Enumerates the output types + + Output stream index + Enumeration of supported output types + + + + Querys whether a specified input type is supported + + Input stream index + Media type to check + true if supports + + + + Sets the input type helper method + + Input stream index + Media type + Flags (can be used to test rather than set) + + + + Sets the input type + + Input stream index + Media Type + + + + Sets the input type to the specified Wave format + + Input stream index + Wave format + + + + Requests whether the specified Wave format is supported as an input + + Input stream index + Wave format + true if supported + + + + Helper function to make a DMO Media Type to represent a particular WaveFormat + + + + + Checks if a specified output type is supported + n.b. you may need to set the input type first + + Output stream index + Media type + True if supported + + + + Tests if the specified Wave Format is supported for output + n.b. may need to set the input type first + + Output stream index + Wave format + True if supported + + + + Helper method to call SetOutputType + + + + + Sets the output type + n.b. may need to set the input type first + + Output stream index + Media type to set + + + + Set output type to the specified wave format + n.b. may need to set input type first + + Output stream index + Wave format + + + + Get Input Size Info + + Input Stream Index + Input Size Info + + + + Get Output Size Info + + Output Stream Index + Output Size Info + + + + Process Input + + Input Stream index + Media Buffer + Flags + Timestamp + Duration + + + + Process Output + + Flags + Output buffer count + Output buffers + + + + Gives the DMO a chance to allocate any resources needed for streaming + + + + + Tells the DMO to free any resources needed for streaming + + + + + Gets maximum input latency + + input stream index + Maximum input latency as a ref-time + + + + Flushes all buffered data + + + + + Report a discontinuity on the specified input stream + + Input Stream index + + + + Is this input stream accepting data? + + Input Stream index + true if accepting data + + + + Experimental code, not currently being called + Not sure if it is necessary anyway + + + + + Media Object Size Info + + + + + Minimum Buffer Size, in bytes + + + + + Max Lookahead + + + + + Alignment + + + + + Media Object Size Info + + + + + ToString + + + + + MP_PARAMINFO + + + + + MP_TYPE + + + + + MPT_INT + + + + + MPT_FLOAT + + + + + MPT_BOOL + + + + + MPT_ENUM + + + + + MPT_MAX + + + + + MP_CURVE_TYPE + + + + + uuids.h, ksuuids.h + + + + + implements IMediaObject (DirectX Media Object) + implements IMFTransform (Media Foundation Transform) + On Windows XP, it is always an MM (if present at all) + + + + + Windows Media MP3 Decoder (as a DMO) + WORK IN PROGRESS - DO NOT USE! + + + + + Creates a new Resampler based on the DMO Resampler + + + + + Media Object + + + + + Dispose code - experimental at the moment + Was added trying to track down why Resampler crashes NUnit + This code not currently being called by ResamplerDmoStream + + + + + DMO Input Data Buffer Flags + + + + + None + + + + + DMO_INPUT_DATA_BUFFERF_SYNCPOINT + + + + + DMO_INPUT_DATA_BUFFERF_TIME + + + + + DMO_INPUT_DATA_BUFFERF_TIMELENGTH + + + + + http://msdn.microsoft.com/en-us/library/aa929922.aspx + DMO_MEDIA_TYPE + + + + + Major type + + + + + Major type name + + + + + Subtype + + + + + Subtype name + + + + + Fixed size samples + + + + + Sample size + + + + + Format type + + + + + Format type name + + + + + Gets the structure as a Wave format (if it is one) + + + + + Sets this object up to point to a wave format + + Wave format structure + + + + DMO Output Data Buffer + + + + + Creates a new DMO Output Data Buffer structure + + Maximum buffer size + + + + Dispose + + + + + Media Buffer + + + + + Length of data in buffer + + + + + Status Flags + + + + + Timestamp + + + + + Duration + + + + + Retrives the data in this buffer + + Buffer to receive data + Offset into buffer + + + + Is more data available + If true, ProcessOuput should be called again + + + + + DMO Output Data Buffer Flags + + + + + None + + + + + DMO_OUTPUT_DATA_BUFFERF_SYNCPOINT + + + + + DMO_OUTPUT_DATA_BUFFERF_TIME + + + + + DMO_OUTPUT_DATA_BUFFERF_TIMELENGTH + + + + + DMO_OUTPUT_DATA_BUFFERF_INCOMPLETE + + + + + DMO Process Output Flags + + + + + None + + + + + DMO_PROCESS_OUTPUT_DISCARD_WHEN_NO_BUFFER + + + + + IMediaBuffer Interface + + + + + Set Length + + Length + HRESULT + + + + Get Max Length + + Max Length + HRESULT + + + + Get Buffer and Length + + Pointer to variable into which to write the Buffer Pointer + Pointer to variable into which to write the Valid Data Length + HRESULT + + + + defined in mediaobj.h + + + + + From wmcodecsdp.h + Implements: + - IMediaObject + - IMFTransform (Media foundation - we will leave this for now as there is loads of MF stuff) + - IPropertyStore + - IWMResamplerProps + Can resample PCM or IEEE + + + + + DMO Resampler + + + + + Creates a new Resampler based on the DMO Resampler + + + + + Media Object + + + + + Dispose code - experimental at the moment + Was added trying to track down why Resampler crashes NUnit + This code not currently being called by ResamplerDmoStream + + + + + Soundfont generator + + + + + Gets the generator type + + + + + Generator amount as an unsigned short + + + + + Generator amount as a signed short + + + + + Low byte amount + + + + + High byte amount + + + + + Instrument + + + + + Sample Header + + + + + + + + + + Generator types + + + + Start address offset + + + End address offset + + + Start loop address offset + + + End loop address offset + + + Start address coarse offset + + + Modulation LFO to pitch + + + Vibrato LFO to pitch + + + Modulation envelope to pitch + + + Initial filter cutoff frequency + + + Initial filter Q + + + Modulation LFO to filter Cutoff frequency + + + Modulation envelope to filter cutoff frequency + + + End address coarse offset + + + Modulation LFO to volume + + + Unused + + + Chorus effects send + + + Reverb effects send + + + Pan + + + Unused + + + Unused + + + Unused + + + Delay modulation LFO + + + Frequency modulation LFO + + + Delay vibrato LFO + + + Frequency vibrato LFO + + + Delay modulation envelope + + + Attack modulation envelope + + + Hold modulation envelope + + + Decay modulation envelope + + + Sustain modulation envelop + + + Release modulation envelope + + + Key number to modulation envelope hold + + + Key number to modulation envelope decay + + + Delay volume envelope + + + Attack volume envelope + + + Hold volume envelope + + + Decay volume envelope + + + Sustain volume envelope + + + Release volume envelope + + + Key number to volume envelope hold + + + Key number to volume envelope decay + + + Instrument + + + Reserved + + + Key range + + + Velocity range + + + Start loop address coarse offset + + + Key number + + + Velocity + + + Initial attenuation + + + Reserved + + + End loop address coarse offset + + + Coarse tune + + + Fine tune + + + Sample ID + + + Sample modes + + + Reserved + + + Scale tuning + + + Exclusive class + + + Overriding root key + + + Unused + + + Unused + + + + A soundfont info chunk + + + + + SoundFont Version + + + + + WaveTable sound engine + + + + + Bank name + + + + + Data ROM + + + + + Creation Date + + + + + Author + + + + + Target Product + + + + + Copyright + + + + + Comments + + + + + Tools + + + + + ROM Version + + + + + + + + + + SoundFont instrument + + + + + instrument name + + + + + Zones + + + + + + + + + + Instrument Builder + + + + + Transform Types + + + + + Linear + + + + + Modulator + + + + + Source Modulation data type + + + + + Destination generator type + + + + + Amount + + + + + Source Modulation Amount Type + + + + + Source Transform Type + + + + + + + + + + Controller Sources + + + + + No Controller + + + + + Note On Velocity + + + + + Note On Key Number + + + + + Poly Pressure + + + + + Channel Pressure + + + + + Pitch Wheel + + + + + Pitch Wheel Sensitivity + + + + + Source Types + + + + + Linear + + + + + Concave + + + + + Convex + + + + + Switch + + + + + Modulator Type + + + + + + + + + + + A SoundFont Preset + + + + + Preset name + + + + + Patch Number + + + + + Bank number + + + + + Zones + + + + + + + + + + Class to read the SoundFont file presets chunk + + + + + The Presets contained in this chunk + + + + + The instruments contained in this chunk + + + + + The sample headers contained in this chunk + + + + + + + + + + just reads a chunk ID at the current position + + chunk ID + + + + reads a chunk at the current position + + + + + creates a new riffchunk from current position checking that we're not + at the end of this chunk first + + the new chunk + + + + useful for chunks that just contain a string + + chunk as string + + + + A SoundFont Sample Header + + + + + The sample name + + + + + Start offset + + + + + End offset + + + + + Start loop point + + + + + End loop point + + + + + Sample Rate + + + + + Original pitch + + + + + Pitch correction + + + + + Sample Link + + + + + SoundFont Sample Link Type + + + + + + + + + + SoundFont sample modes + + + + + No loop + + + + + Loop Continuously + + + + + Reserved no loop + + + + + Loop and continue + + + + + Sample Link Type + + + + + Mono Sample + + + + + Right Sample + + + + + Left Sample + + + + + Linked Sample + + + + + ROM Mono Sample + + + + + ROM Right Sample + + + + + ROM Left Sample + + + + + ROM Linked Sample + + + + + SoundFont Version Structure + + + + + Major Version + + + + + Minor Version + + + + + Builds a SoundFont version + + + + + Reads a SoundFont Version structure + + + + + Writes a SoundFont Version structure + + + + + Gets the length of this structure + + + + + Represents a SoundFont + + + + + Loads a SoundFont from a file + + Filename of the SoundFont + + + + Loads a SoundFont from a stream + + stream + + + + The File Info Chunk + + + + + The Presets + + + + + The Instruments + + + + + The Sample Headers + + + + + The Sample Data + + + + + + + + + + base class for structures that can read themselves + + + + + A SoundFont zone + + + + + + + + + + Modulators for this Zone + + + + + Generators for this Zone + + + + + Summary description for Fader. + + + + + Required designer variable. + + + + + Creates a new Fader control + + + + + Clean up any resources being used. + + + + + + + + + + + + + + + + + + + + + + + + + Minimum value of this fader + + + + + Maximum value of this fader + + + + + Current value of this fader + + + + + Fader orientation + + + + + Required method for Designer support - do not modify + the contents of this method with the code editor. + + + + + Pan slider control + + + + + Required designer variable. + + + + + True when pan value changed + + + + + Creates a new PanSlider control + + + + + Clean up any resources being used. + + + + + Required method for Designer support - do not modify + the contents of this method with the code editor. + + + + + + + + + + + + + + + + + + + + + The current Pan setting + + + + + Control that represents a potentiometer + TODO list: + Optional Log scale + Optional reverse scale + Keyboard control + Optional bitmap mode + Optional complete draw mode + Tooltip support + + + + + Value changed event + + + + + Creates a new pot control + + + + + Minimum Value of the Pot + + + + + Maximum Value of the Pot + + + + + The current value of the pot + + + + + Draws the control + + + + + Handles the mouse down event to allow changing value by dragging + + + + + Handles the mouse up event to allow changing value by dragging + + + + + Handles the mouse down event to allow changing value by dragging + + + + + Required designer variable. + + + + + Clean up any resources being used. + + true if managed resources should be disposed; otherwise, false. + + + + Required method for Designer support - do not modify + the contents of this method with the code editor. + + + + + Implements a rudimentary volume meter + + + + + Basic volume meter + + + + + On Fore Color Changed + + + + + Current Value + + + + + Minimum decibels + + + + + Maximum decibels + + + + + Meter orientation + + + + + Paints the volume meter + + + + + Required designer variable. + + + + + Clean up any resources being used. + + true if managed resources should be disposed; otherwise, false. + + + + Required method for Designer support - do not modify + the contents of this method with the code editor. + + + + + VolumeSlider control + + + + + Required designer variable. + + + + + Volume changed event + + + + + Creates a new VolumeSlider control + + + + + Clean up any resources being used. + + + + + Required method for Designer support - do not modify + the contents of this method with the code editor. + + + + + + + + + + + + + + + + + + + + The volume for this control + + + + + Windows Forms control for painting audio waveforms + + + + + Constructs a new instance of the WaveFormPainter class + + + + + On Resize + + + + + On ForeColor Changed + + + + + + Add Max Value + + + + + + On Paint + + + + + Required designer variable. + + + + + Clean up any resources being used. + + true if managed resources should be disposed; otherwise, false. + + + + Required method for Designer support - do not modify + the contents of this method with the code editor. + + + + + Control for viewing waveforms + + + + + Required designer variable. + + + + + Creates a new WaveViewer control + + + + + sets the associated wavestream + + + + + The zoom level, in samples per pixel + + + + + Start position (currently in bytes) + + + + + Clean up any resources being used. + + + + + + + + + + Required method for Designer support - do not modify + the contents of this method with the code editor. + + + + + Boolean mixer control + + + + + Gets the details for this control + + memory pointer + + + + The current value of the control + + + + + Custom Mixer control + + + + + Get the data for this custom control + + pointer to memory to receive data + + + + List text mixer control + + + + + Get the details for this control + + Memory location to read to + + + Represents a Windows mixer device + + + The number of mixer devices available + + + Connects to the specified mixer + The index of the mixer to use. + This should be between zero and NumberOfDevices - 1 + + + The number of destinations this mixer supports + + + The name of this mixer device + + + The manufacturer code for this mixer device + + + The product identifier code for this mixer device + + + Retrieve the specified MixerDestination object + The ID of the destination to use. + Should be between 0 and DestinationCount - 1 + + + + A way to enumerate the destinations + + + + + A way to enumerate all available devices + + + + + Represents a mixer control + + + + + Mixer Handle + + + + + Number of Channels + + + + + Mixer Handle Type + + + + + Gets all the mixer controls + + Mixer Handle + Mixer Line + Mixer Handle Type + + + + + Gets a specified Mixer Control + + Mixer Handle + Line ID + Control ID + Number of Channels + Flags to use (indicates the meaning of mixerHandle) + + + + + Gets the control details + + + + + Gets the control details + + + + + + Mixer control name + + + + + Mixer control type + + + + + Returns true if this is a boolean control + + Control type + + + + Is this a boolean control + + + + + Determines whether a specified mixer control type is a list text control + + + + + True if this is a list text control + + + + + True if this is a signed control + + + + + True if this is an unsigned control + + + + + True if this is a custom control + + + + + String representation for debug purposes + + + + + Mixer control types + + + + Custom + + + Boolean meter + + + Signed meter + + + Peak meter + + + Unsigned meter + + + Boolean + + + On Off + + + Mute + + + Mono + + + Loudness + + + Stereo Enhance + + + Button + + + Decibels + + + Signed + + + Unsigned + + + Percent + + + Slider + + + Pan + + + Q-sound pan + + + Fader + + + Volume + + + Bass + + + Treble + + + Equaliser + + + Single Select + + + Mux + + + Multiple select + + + Mixer + + + Micro time + + + Milli time + + + + Represents a mixer line (source or destination) + + + + + Creates a new mixer destination + + Mixer Handle + Destination Index + Mixer Handle Type + + + + Creates a new Mixer Source For a Specified Source + + Mixer Handle + Destination Index + Source Index + Flag indicating the meaning of mixerHandle + + + + Creates a new Mixer Source + + Wave In Device + + + + Mixer Line Name + + + + + Mixer Line short name + + + + + The line ID + + + + + Component Type + + + + + Mixer destination type description + + + + + Number of channels + + + + + Number of sources + + + + + Number of controls + + + + + Is this destination active + + + + + Is this destination disconnected + + + + + Is this destination a source + + + + + Gets the specified source + + + + + Enumerator for the controls on this Mixer Limne + + + + + Enumerator for the sources on this Mixer Line + + + + + The name of the target output device + + + + + Describes this Mixer Line (for diagnostic purposes) + + + + + Mixer Interop Flags + + + + + MIXER_OBJECTF_HANDLE = 0x80000000; + + + + + MIXER_OBJECTF_MIXER = 0x00000000; + + + + + MIXER_OBJECTF_HMIXER + + + + + MIXER_OBJECTF_WAVEOUT + + + + + MIXER_OBJECTF_HWAVEOUT + + + + + MIXER_OBJECTF_WAVEIN + + + + + MIXER_OBJECTF_HWAVEIN + + + + + MIXER_OBJECTF_MIDIOUT + + + + + MIXER_OBJECTF_HMIDIOUT + + + + + MIXER_OBJECTF_MIDIIN + + + + + MIXER_OBJECTF_HMIDIIN + + + + + MIXER_OBJECTF_AUX + + + + + MIXER_GETCONTROLDETAILSF_VALUE = 0x00000000; + MIXER_SETCONTROLDETAILSF_VALUE = 0x00000000; + + + + + MIXER_GETCONTROLDETAILSF_LISTTEXT = 0x00000001; + MIXER_SETCONTROLDETAILSF_LISTTEXT = 0x00000001; + + + + + MIXER_GETCONTROLDETAILSF_QUERYMASK = 0x0000000F; + MIXER_SETCONTROLDETAILSF_QUERYMASK = 0x0000000F; + MIXER_GETLINECONTROLSF_QUERYMASK = 0x0000000F; + + + + + MIXER_GETLINECONTROLSF_ALL = 0x00000000; + + + + + MIXER_GETLINECONTROLSF_ONEBYID = 0x00000001; + + + + + MIXER_GETLINECONTROLSF_ONEBYTYPE = 0x00000002; + + + + + MIXER_GETLINEINFOF_DESTINATION = 0x00000000; + + + + + MIXER_GETLINEINFOF_SOURCE = 0x00000001; + + + + + MIXER_GETLINEINFOF_LINEID = 0x00000002; + + + + + MIXER_GETLINEINFOF_COMPONENTTYPE = 0x00000003; + + + + + MIXER_GETLINEINFOF_TARGETTYPE = 0x00000004; + + + + + MIXER_GETLINEINFOF_QUERYMASK = 0x0000000F; + + + + + Mixer Line Flags + + + + + Audio line is active. An active line indicates that a signal is probably passing + through the line. + + + + + Audio line is disconnected. A disconnected line's associated controls can still be + modified, but the changes have no effect until the line is connected. + + + + + Audio line is an audio source line associated with a single audio destination line. + If this flag is not set, this line is an audio destination line associated with zero + or more audio source lines. + + + + + BOUNDS structure + + + + + dwMinimum / lMinimum / reserved 0 + + + + + dwMaximum / lMaximum / reserved 1 + + + + + reserved 2 + + + + + reserved 3 + + + + + reserved 4 + + + + + reserved 5 + + + + + METRICS structure + + + + + cSteps / reserved[0] + + + + + cbCustomData / reserved[1], number of bytes for control details + + + + + reserved 2 + + + + + reserved 3 + + + + + reserved 4 + + + + + reserved 5 + + + + + MIXERCONTROL struct + http://msdn.microsoft.com/en-us/library/dd757293%28VS.85%29.aspx + + + + + Mixer Line Component type enumeration + + + + + Audio line is a destination that cannot be defined by one of the standard component types. A mixer device is required to use this component type for line component types that have not been defined by Microsoft Corporation. + MIXERLINE_COMPONENTTYPE_DST_UNDEFINED + + + + + Audio line is a digital destination (for example, digital input to a DAT or CD audio device). + MIXERLINE_COMPONENTTYPE_DST_DIGITAL + + + + + Audio line is a line level destination (for example, line level input from a CD audio device) that will be the final recording source for the analog-to-digital converter (ADC). Because most audio cards for personal computers provide some sort of gain for the recording audio source line, the mixer device will use the MIXERLINE_COMPONENTTYPE_DST_WAVEIN type. + MIXERLINE_COMPONENTTYPE_DST_LINE + + + + + Audio line is a destination used for a monitor. + MIXERLINE_COMPONENTTYPE_DST_MONITOR + + + + + Audio line is an adjustable (gain and/or attenuation) destination intended to drive speakers. This is the typical component type for the audio output of audio cards for personal computers. + MIXERLINE_COMPONENTTYPE_DST_SPEAKERS + + + + + Audio line is an adjustable (gain and/or attenuation) destination intended to drive headphones. Most audio cards use the same audio destination line for speakers and headphones, in which case the mixer device simply uses the MIXERLINE_COMPONENTTYPE_DST_SPEAKERS type. + MIXERLINE_COMPONENTTYPE_DST_HEADPHONES + + + + + Audio line is a destination that will be routed to a telephone line. + MIXERLINE_COMPONENTTYPE_DST_TELEPHONE + + + + + Audio line is a destination that will be the final recording source for the waveform-audio input (ADC). This line typically provides some sort of gain or attenuation. This is the typical component type for the recording line of most audio cards for personal computers. + MIXERLINE_COMPONENTTYPE_DST_WAVEIN + + + + + Audio line is a destination that will be the final recording source for voice input. This component type is exactly like MIXERLINE_COMPONENTTYPE_DST_WAVEIN but is intended specifically for settings used during voice recording/recognition. Support for this line is optional for a mixer device. Many mixer devices provide only MIXERLINE_COMPONENTTYPE_DST_WAVEIN. + MIXERLINE_COMPONENTTYPE_DST_VOICEIN + + + + + Audio line is a source that cannot be defined by one of the standard component types. A mixer device is required to use this component type for line component types that have not been defined by Microsoft Corporation. + MIXERLINE_COMPONENTTYPE_SRC_UNDEFINED + + + + + Audio line is a digital source (for example, digital output from a DAT or audio CD). + MIXERLINE_COMPONENTTYPE_SRC_DIGITAL + + + + + Audio line is a line-level source (for example, line-level input from an external stereo) that can be used as an optional recording source. Because most audio cards for personal computers provide some sort of gain for the recording source line, the mixer device will use the MIXERLINE_COMPONENTTYPE_SRC_AUXILIARY type. + MIXERLINE_COMPONENTTYPE_SRC_LINE + + + + + Audio line is a microphone recording source. Most audio cards for personal computers provide at least two types of recording sources: an auxiliary audio line and microphone input. A microphone audio line typically provides some sort of gain. Audio cards that use a single input for use with a microphone or auxiliary audio line should use the MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE component type. + MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE + + + + + Audio line is a source originating from the output of an internal synthesizer. Most audio cards for personal computers provide some sort of MIDI synthesizer (for example, an Adlib®-compatible or OPL/3 FM synthesizer). + MIXERLINE_COMPONENTTYPE_SRC_SYNTHESIZER + + + + + Audio line is a source originating from the output of an internal audio CD. This component type is provided for audio cards that provide an audio source line intended to be connected to an audio CD (or CD-ROM playing an audio CD). + MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC + + + + + Audio line is a source originating from an incoming telephone line. + MIXERLINE_COMPONENTTYPE_SRC_TELEPHONE + + + + + Audio line is a source originating from personal computer speaker. Several audio cards for personal computers provide the ability to mix what would typically be played on the internal speaker with the output of an audio card. Some audio cards support the ability to use this output as a recording source. + MIXERLINE_COMPONENTTYPE_SRC_PCSPEAKER + + + + + Audio line is a source originating from the waveform-audio output digital-to-analog converter (DAC). Most audio cards for personal computers provide this component type as a source to the MIXERLINE_COMPONENTTYPE_DST_SPEAKERS destination. Some cards also allow this source to be routed to the MIXERLINE_COMPONENTTYPE_DST_WAVEIN destination. + MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT + + + + + Audio line is a source originating from the auxiliary audio line. This line type is intended as a source with gain or attenuation that can be routed to the MIXERLINE_COMPONENTTYPE_DST_SPEAKERS destination and/or recorded from the MIXERLINE_COMPONENTTYPE_DST_WAVEIN destination. + MIXERLINE_COMPONENTTYPE_SRC_AUXILIARY + + + + + Audio line is an analog source (for example, analog output from a video-cassette tape). + MIXERLINE_COMPONENTTYPE_SRC_ANALOG + + + + + Represents a signed mixer control + + + + + Gets details for this contrl + + + + + The value of the control + + + + + Minimum value for this control + + + + + Maximum value for this control + + + + + Value of the control represented as a percentage + + + + + String Representation for debugging purposes + + + + + + Represents an unsigned mixer control + + + + + Gets the details for this control + + + + + The control value + + + + + The control's minimum value + + + + + The control's maximum value + + + + + Value of the control represented as a percentage + + + + + String Representation for debugging purposes + + + + + Manufacturer codes from mmreg.h + + + + Microsoft Corporation + + + Creative Labs, Inc + + + Media Vision, Inc. + + + Fujitsu Corp. + + + Artisoft, Inc. + + + Turtle Beach, Inc. + + + IBM Corporation + + + Vocaltec LTD. + + + Roland + + + DSP Solutions, Inc. + + + NEC + + + ATI + + + Wang Laboratories, Inc + + + Tandy Corporation + + + Voyetra + + + Antex Electronics Corporation + + + ICL Personal Systems + + + Intel Corporation + + + Advanced Gravis + + + Video Associates Labs, Inc. + + + InterActive Inc + + + Yamaha Corporation of America + + + Everex Systems, Inc + + + Echo Speech Corporation + + + Sierra Semiconductor Corp + + + Computer Aided Technologies + + + APPS Software International + + + DSP Group, Inc + + + microEngineering Labs + + + Computer Friends, Inc. + + + ESS Technology + + + Audio, Inc. + + + Motorola, Inc. + + + Canopus, co., Ltd. + + + Seiko Epson Corporation + + + Truevision + + + Aztech Labs, Inc. + + + Videologic + + + SCALACS + + + Korg Inc. + + + Audio Processing Technology + + + Integrated Circuit Systems, Inc. + + + Iterated Systems, Inc. + + + Metheus + + + Logitech, Inc. + + + Winnov, Inc. + + + NCR Corporation + + + EXAN + + + AST Research Inc. + + + Willow Pond Corporation + + + Sonic Foundry + + + Vitec Multimedia + + + MOSCOM Corporation + + + Silicon Soft, Inc. + + + Supermac + + + Audio Processing Technology + + + Speech Compression + + + Ahead, Inc. + + + Dolby Laboratories + + + OKI + + + AuraVision Corporation + + + Ing C. Olivetti & C., S.p.A. + + + I/O Magic Corporation + + + Matsushita Electric Industrial Co., LTD. + + + Control Resources Limited + + + Xebec Multimedia Solutions Limited + + + New Media Corporation + + + Natural MicroSystems + + + Lyrrus Inc. + + + Compusic + + + OPTi Computers Inc. + + + Adlib Accessories Inc. + + + Compaq Computer Corp. + + + Dialogic Corporation + + + InSoft, Inc. + + + M.P. Technologies, Inc. + + + Weitek + + + Lernout & Hauspie + + + Quanta Computer Inc. + + + Apple Computer, Inc. + + + Digital Equipment Corporation + + + Mark of the Unicorn + + + Workbit Corporation + + + Ositech Communications Inc. + + + miro Computer Products AG + + + Cirrus Logic + + + ISOLUTION B.V. + + + Horizons Technology, Inc + + + Computer Concepts Ltd + + + Voice Technologies Group, Inc. + + + Radius + + + Rockwell International + + + Co. XYZ for testing + + + Opcode Systems + + + Voxware Inc + + + Northern Telecom Limited + + + APICOM + + + Grande Software + + + ADDX + + + Wildcat Canyon Software + + + Rhetorex Inc + + + Brooktree Corporation + + + ENSONIQ Corporation + + + FAST Multimedia AG + + + NVidia Corporation + + + OKSORI Co., Ltd. + + + DiAcoustics, Inc. + + + Gulbransen, Inc. + + + Kay Elemetrics, Inc. + + + Crystal Semiconductor Corporation + + + Splash Studios + + + Quarterdeck Corporation + + + TDK Corporation + + + Digital Audio Labs, Inc. + + + Seer Systems, Inc. + + + PictureTel Corporation + + + AT&T Microelectronics + + + Osprey Technologies, Inc. + + + Mediatrix Peripherals + + + SounDesignS M.C.S. Ltd. + + + A.L. Digital Ltd. + + + Spectrum Signal Processing, Inc. + + + Electronic Courseware Systems, Inc. + + + AMD + + + Core Dynamics + + + CANAM Computers + + + Softsound, Ltd. + + + Norris Communications, Inc. + + + Danka Data Devices + + + EuPhonics + + + Precept Software, Inc. + + + Crystal Net Corporation + + + Chromatic Research, Inc + + + Voice Information Systems, Inc + + + Vienna Systems + + + Connectix Corporation + + + Gadget Labs LLC + + + Frontier Design Group LLC + + + Viona Development GmbH + + + Casio Computer Co., LTD + + + Diamond Multimedia + + + S3 + + + Fraunhofer + + + + Summary description for MmException. + + + + + Creates a new MmException + + The result returned by the Windows API call + The name of the Windows API that failed + + + + Helper function to automatically raise an exception on failure + + The result of the API call + The API function name + + + + Returns the Windows API result + + + + + Windows multimedia error codes from mmsystem.h. + + + + no error, MMSYSERR_NOERROR + + + unspecified error, MMSYSERR_ERROR + + + device ID out of range, MMSYSERR_BADDEVICEID + + + driver failed enable, MMSYSERR_NOTENABLED + + + device already allocated, MMSYSERR_ALLOCATED + + + device handle is invalid, MMSYSERR_INVALHANDLE + + + no device driver present, MMSYSERR_NODRIVER + + + memory allocation error, MMSYSERR_NOMEM + + + function isn't supported, MMSYSERR_NOTSUPPORTED + + + error value out of range, MMSYSERR_BADERRNUM + + + invalid flag passed, MMSYSERR_INVALFLAG + + + invalid parameter passed, MMSYSERR_INVALPARAM + + + handle being used simultaneously on another thread (eg callback),MMSYSERR_HANDLEBUSY + + + specified alias not found, MMSYSERR_INVALIDALIAS + + + bad registry database, MMSYSERR_BADDB + + + registry key not found, MMSYSERR_KEYNOTFOUND + + + registry read error, MMSYSERR_READERROR + + + registry write error, MMSYSERR_WRITEERROR + + + registry delete error, MMSYSERR_DELETEERROR + + + registry value not found, MMSYSERR_VALNOTFOUND + + + driver does not call DriverCallback, MMSYSERR_NODRIVERCB + + + more data to be returned, MMSYSERR_MOREDATA + + + unsupported wave format, WAVERR_BADFORMAT + + + still something playing, WAVERR_STILLPLAYING + + + header not prepared, WAVERR_UNPREPARED + + + device is synchronous, WAVERR_SYNC + + + Conversion not possible (ACMERR_NOTPOSSIBLE) + + + Busy (ACMERR_BUSY) + + + Header Unprepared (ACMERR_UNPREPARED) + + + Cancelled (ACMERR_CANCELED) + + + invalid line (MIXERR_INVALLINE) + + + invalid control (MIXERR_INVALCONTROL) + + + invalid value (MIXERR_INVALVALUE) + + + diff --git a/Assets/Plugins/NAudio/NAudio.xml.meta b/Assets/Plugins/NAudio/NAudio.xml.meta new file mode 100644 index 00000000..40e8eb9c --- /dev/null +++ b/Assets/Plugins/NAudio/NAudio.xml.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 192b3ed9512299043ac35bc59105e17e +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/NAudio/license.txt b/Assets/Plugins/NAudio/license.txt new file mode 100644 index 00000000..622a544b --- /dev/null +++ b/Assets/Plugins/NAudio/license.txt @@ -0,0 +1,31 @@ +Microsoft Public License (Ms-PL) + +This license governs use of the accompanying software. If you use the software, you accept this license. If you do not accept the license, do not use the software. + +1. Definitions + +The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here as under U.S. copyright law. + +A "contribution" is the original software, or any additions or changes to the software. + +A "contributor" is any person that distributes its contribution under this license. + +"Licensed patents" are a contributor's patent claims that read directly on its contribution. + +2. Grant of Rights + +(A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create. + +(B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software. + +3. Conditions and Limitations + +(A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks. + +(B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically. + +(C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software. + +(D) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license. + +(E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement. \ No newline at end of file diff --git a/Assets/Plugins/NAudio/license.txt.meta b/Assets/Plugins/NAudio/license.txt.meta new file mode 100644 index 00000000..484ddbaa --- /dev/null +++ b/Assets/Plugins/NAudio/license.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 85c47de6dc00d9347944c83b7b1aa061 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/NAudio/readme.txt b/Assets/Plugins/NAudio/readme.txt new file mode 100644 index 00000000..0ac6523a --- /dev/null +++ b/Assets/Plugins/NAudio/readme.txt @@ -0,0 +1,92 @@ +NAudio is an open source .NET audio library written by Mark Heath (mark.heath@gmail.com) +For more information, visit http://naudio.codeplex.com +NAudio is now being hosted on GitHub http://github.com/naudio/NAudio + +THANKS +====== +The following list includes some of the people who have contributed in various ways to NAudio, such as code contributions, +bug fixes, documentation, helping out on the forums and even donations. I haven't finished compiling this list yet, so +if your name should be on it but isn't please let me know and I will include it. Also, some people I only know by their forum +id, so if you want me to put your full name here, please also get in touch. + +in alphabetical order: +Alan Jordan +Alexandre Mutel +Alexander Binkert +AmandaTarafaMas +balistof +biermeester +borman11 +bradb +Brandon Hansen (kg6ypi) +csechet +ChunkWare Music Software +CKing +DaMacc +Dirk Eckhardt +Du10 +eejake52 +Florian Rosmann (filoe) +Freefall +Giawa +Harald Petrovitsch +Hfuy +Iain McCowan +Idael Cardaso +ioctlLR +Ivan Kochurkin (KvanTTT) +Jamie Michael Ewins +jannera +jbaker8935 +jcameron23 +JoeGaggler +jonahoffmann +jontdelorme +Jospin Software +Justin Frankel +K24A3 +Kamen Lichev +Kassoul +kevinxxx +kzych +LionCash +Lustild +Lucian Wischik (ljw1004) +ManuN +MeelMarcel +Michael Chadwick +Michael Feld +Michael J +Michael Lehenbauer +milligan22963 +myrkle +nelsonkidd +Nigel Redmon +Nikolaos Georgiou +Owen Skriloff +owoudenb +painmailer +PPavan +Pygmy +Ray Molenkamp +Roadz +Robert Bristow-Johnson +Scott Fleischman +Simon Clark +Sirish Bajpai +sporn +Steve Underwood +Ted Murphy +Tiny Simple Tools +Tobias Fleming +TomBogle +Tony Cabello +Tony Sistemas +TuneBlade +topher3683 +volmart +Vladimir Rokovanov +Ville Koskinen +Wyatt Rice +Yuval Naveh +Zsb diff --git a/Assets/Plugins/NAudio/readme.txt.meta b/Assets/Plugins/NAudio/readme.txt.meta new file mode 100644 index 00000000..d73d0cc8 --- /dev/null +++ b/Assets/Plugins/NAudio/readme.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: dce5cec6770b7814ab66c6b15147547b +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Prefabs/Scene Startup.prefab b/Assets/Prefabs/Startup.prefab similarity index 65% rename from Assets/Prefabs/Scene Startup.prefab rename to Assets/Prefabs/Startup.prefab index 88c8f019..d19175b8 100644 --- a/Assets/Prefabs/Scene Startup.prefab +++ b/Assets/Prefabs/Startup.prefab @@ -9,8 +9,8 @@ GameObject: serializedVersion: 6 m_Component: - component: {fileID: 1882356792} - - component: {fileID: 1882356793} - component: {fileID: 1496312898662852549} + - component: {fileID: 2609597518647025629} m_Layer: 0 m_Name: Music Source m_TagString: Untagged @@ -32,103 +32,19 @@ Transform: m_Father: {fileID: 2467515431058217606} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!82 &1882356793 -AudioSource: +--- !u!114 &1496312898662852549 +MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1882356791} m_Enabled: 1 - serializedVersion: 4 - OutputAudioMixerGroup: {fileID: 0} - m_audioClip: {fileID: 0} - m_PlayOnAwake: 0 - m_Volume: 1 - m_Pitch: 1 - Loop: 1 - Mute: 0 - Spatialize: 0 - SpatializePostEffects: 0 - Priority: 128 - DopplerLevel: 1 - MinDistance: 1 - MaxDistance: 500 - Pan2D: 0 - rolloffMode: 0 - BypassEffects: 0 - BypassListenerEffects: 0 - BypassReverbZones: 0 - rolloffCustomCurve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 1 - inSlope: 0 - outSlope: 0 - tangentMode: 0 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 1 - value: 0 - inSlope: 0 - outSlope: 0 - tangentMode: 0 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - panLevelCustomCurve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0 - inSlope: 0 - outSlope: 0 - tangentMode: 0 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - spreadCustomCurve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0 - inSlope: 0 - outSlope: 0 - tangentMode: 0 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - reverbZoneMixCustomCurve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 1 - inSlope: 0 - outSlope: 0 - tangentMode: 0 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 ---- !u!114 &1496312898662852549 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0a672653ec2ecb14588349889a32be1e, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!114 &2609597518647025629 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -137,9 +53,12 @@ MonoBehaviour: m_GameObject: {fileID: 1882356791} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 0a672653ec2ecb14588349889a32be1e, type: 3} + m_Script: {fileID: 11500000, guid: a36a87e28e05b91479c6b0d82765f248, type: 3} m_Name: m_EditorClassIdentifier: + Mixer: 2 + Loop: 1 + Volume: 1 --- !u!1 &2467515431058217605 GameObject: m_ObjectHideFlags: 0 @@ -149,11 +68,12 @@ GameObject: serializedVersion: 6 m_Component: - component: {fileID: 2467515431058217606} + - component: {fileID: 7238001765745231388} + - component: {fileID: 1681581118} - component: {fileID: 6889856724969260489} - component: {fileID: 5395210396068068221} - - component: {fileID: 1681581118} m_Layer: 0 - m_Name: Scene Startup + m_Name: Startup m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 @@ -174,7 +94,7 @@ Transform: m_Father: {fileID: 0} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!114 &6889856724969260489 +--- !u!114 &7238001765745231388 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -183,11 +103,11 @@ MonoBehaviour: m_GameObject: {fileID: 2467515431058217605} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: a11dab247d664a4429cce4d74d1ac30d, type: 3} + m_Script: {fileID: 11500000, guid: ad304d4d34fd4274e943ffc0fc2d0436, type: 3} m_Name: m_EditorClassIdentifier: - _defaultFont: {fileID: 12800000, guid: 0b89e5cf40aeb5041b1628fc5265cadb, type: 3} ---- !u!114 &5395210396068068221 + TargetScene: Main Menu +--- !u!114 &1681581118 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -196,10 +116,10 @@ MonoBehaviour: m_GameObject: {fileID: 2467515431058217605} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 3a9ce02e546d0c347965dd175518f4f0, type: 3} + m_Script: {fileID: 11500000, guid: 3d47bd7e30123ab43b077d5cb0469b69, type: 3} m_Name: m_EditorClassIdentifier: ---- !u!114 &1681581118 +--- !u!114 &6889856724969260489 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -208,6 +128,19 @@ MonoBehaviour: m_GameObject: {fileID: 2467515431058217605} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 3d47bd7e30123ab43b077d5cb0469b69, type: 3} + m_Script: {fileID: 11500000, guid: a11dab247d664a4429cce4d74d1ac30d, type: 3} + m_Name: + m_EditorClassIdentifier: + _defaultFont: {fileID: 12800000, guid: 0b89e5cf40aeb5041b1628fc5265cadb, type: 3} +--- !u!114 &5395210396068068221 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2467515431058217605} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3a9ce02e546d0c347965dd175518f4f0, type: 3} m_Name: m_EditorClassIdentifier: diff --git a/Assets/Prefabs/Scene Startup.prefab.meta b/Assets/Prefabs/Startup.prefab.meta similarity index 100% rename from Assets/Prefabs/Scene Startup.prefab.meta rename to Assets/Prefabs/Startup.prefab.meta diff --git a/Assets/Scenes/Main Menu.unity b/Assets/Scenes/Main Menu.unity new file mode 100644 index 00000000..2c64a265 --- /dev/null +++ b/Assets/Scenes/Main Menu.unity @@ -0,0 +1,1913 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0.44657898, g: 0.4964133, b: 0.5748178, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 12 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 512 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 256 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 1 + m_PVRDenoiserTypeDirect: 1 + m_PVRDenoiserTypeIndirect: 1 + m_PVRDenoiserTypeAO: 1 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 1 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_LightingSettings: {fileID: 0} +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &6315363 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6315364} + - component: {fileID: 6315367} + - component: {fileID: 6315365} + m_Layer: 5 + m_Name: Scroll View + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6315364 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6315363} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1339770444} + m_Father: {fileID: 1383294979} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 1.6949463, y: -105.1} + m_SizeDelta: {x: -3.3900743, y: 200} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &6315365 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6315363} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1aa08ab6e0800fa44ae55d278d1423e3, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Content: {fileID: 2060532664} + m_Horizontal: 0 + m_Vertical: 1 + m_MovementType: 2 + m_Elasticity: 0.1 + m_Inertia: 0 + m_DecelerationRate: 0.135 + m_ScrollSensitivity: 40 + m_Viewport: {fileID: 1339770444} + m_HorizontalScrollbar: {fileID: 0} + m_VerticalScrollbar: {fileID: 2001754372} + m_HorizontalScrollbarVisibility: 2 + m_VerticalScrollbarVisibility: 1 + m_HorizontalScrollbarSpacing: -3 + m_VerticalScrollbarSpacing: -3 + m_OnValueChanged: + m_PersistentCalls: + m_Calls: [] +--- !u!222 &6315367 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6315363} + m_CullTransparentMesh: 1 +--- !u!1 &19247258 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 19247259} + - component: {fileID: 19247261} + - component: {fileID: 19247260} + - component: {fileID: 19247262} + m_Layer: 5 + m_Name: Initial Load Screen Background + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &19247259 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 19247258} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1118021355} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 1024, y: 768} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &19247260 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 19247258} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1344c3c82d62a2a41a3576d8abb8e3ea, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Texture: {fileID: 0} + m_UVRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 +--- !u!222 &19247261 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 19247258} + m_CullTransparentMesh: 1 +--- !u!114 &19247262 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 19247258} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 68f59c2b02ecd40468c22f3eb960d4bd, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &30129050 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 30129051} + m_Layer: 5 + m_Name: Cheat Console + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &30129051 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 30129050} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 238388069} + - {fileID: 1383294979} + m_Father: {fileID: 188582820} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &188582815 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 188582820} + - component: {fileID: 188582819} + - component: {fileID: 188582818} + - component: {fileID: 188582817} + - component: {fileID: 188582816} + m_Layer: 5 + m_Name: Cheat Console Canvas + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &188582816 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 188582815} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: c7d73af69c9e8614080ca76faff3ae13, type: 3} + m_Name: + m_EditorClassIdentifier: + ConsoleParent: {fileID: 30129050} + CheatInputField: {fileID: 238388070} + ConsoleOutput: {fileID: 2060532662} + ConsoleScroll: {fileID: 6315365} +--- !u!114 &188582817 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 188582815} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreReversedGraphics: 1 + m_BlockingObjects: 0 + m_BlockingMask: + serializedVersion: 2 + m_Bits: 4294967295 +--- !u!114 &188582818 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 188582815} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UiScaleMode: 0 + m_ReferencePixelsPerUnit: 100 + m_ScaleFactor: 1 + m_ReferenceResolution: {x: 800, y: 600} + m_ScreenMatchMode: 0 + m_MatchWidthOrHeight: 0 + m_PhysicalUnit: 3 + m_FallbackScreenDPI: 96 + m_DefaultSpriteDPI: 96 + m_DynamicPixelsPerUnit: 1 + m_PresetInfoIsWorld: 0 +--- !u!223 &188582819 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 188582815} + m_Enabled: 1 + serializedVersion: 3 + m_RenderMode: 0 + m_Camera: {fileID: 0} + m_PlaneDistance: 100 + m_PixelPerfect: 0 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_AdditionalShaderChannelsFlag: 0 + m_SortingLayerID: 0 + m_SortingOrder: 100 + m_TargetDisplay: 0 +--- !u!224 &188582820 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 188582815} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0, y: 0, z: 0} + m_Children: + - {fileID: 30129051} + m_Father: {fileID: 0} + m_RootOrder: 6 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0, y: 0} +--- !u!1 &238388068 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 238388069} + - component: {fileID: 238388072} + - component: {fileID: 238388071} + - component: {fileID: 238388070} + m_Layer: 5 + m_Name: InputField + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &238388069 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 238388068} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1496761002} + - {fileID: 577879792} + m_Father: {fileID: 30129051} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -213.4} + m_SizeDelta: {x: 0, y: 30} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &238388070 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 238388068} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d199490a83bb2b844b9695cbf13b01ef, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 238388071} + m_TextComponent: {fileID: 577879793} + m_Placeholder: {fileID: 1496761003} + m_ContentType: 0 + m_InputType: 0 + m_AsteriskChar: 42 + m_KeyboardType: 0 + m_LineType: 0 + m_HideMobileInput: 0 + m_CharacterValidation: 0 + m_CharacterLimit: 0 + m_OnEndEdit: + m_PersistentCalls: + m_Calls: [] + m_OnValueChanged: + m_PersistentCalls: + m_Calls: [] + m_CaretColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_CustomCaretColor: 0 + m_SelectionColor: {r: 0.65882355, g: 0.80784315, b: 1, a: 0.7529412} + m_Text: + m_CaretBlinkRate: 0.85 + m_CaretWidth: 1 + m_ReadOnly: 0 + m_ShouldActivateOnSelect: 1 +--- !u!114 &238388071 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 238388068} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10911, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &238388072 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 238388068} + m_CullTransparentMesh: 1 +--- !u!1 &322359566 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 322359568} + - component: {fileID: 322359567} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &322359567 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 322359566} + m_Enabled: 1 + serializedVersion: 10 + m_Type: 1 + m_Shape: 0 + m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_UseViewFrustumForShadowCasterCull: 1 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &322359568 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 322359566} + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 3, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!1 &431621066 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 431621069} + - component: {fileID: 431621068} + - component: {fileID: 431621067} + m_Layer: 0 + m_Name: EventSystem + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &431621067 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 431621066} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3} + m_Name: + m_EditorClassIdentifier: + m_HorizontalAxis: Horizontal + m_VerticalAxis: Vertical + m_SubmitButton: Submit + m_CancelButton: Cancel + m_InputActionsPerSecond: 10 + m_RepeatDelay: 0.5 + m_ForceModuleActive: 0 +--- !u!114 &431621068 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 431621066} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3} + m_Name: + m_EditorClassIdentifier: + m_FirstSelected: {fileID: 0} + m_sendNavigationEvents: 1 + m_DragThreshold: 10 +--- !u!4 &431621069 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 431621066} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 5 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &577879791 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 577879792} + - component: {fileID: 577879794} + - component: {fileID: 577879793} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &577879792 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 577879791} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 238388069} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -0.5} + m_SizeDelta: {x: -20, y: -13} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &577879793 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 577879791} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 14 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 10 + m_MaxSize: 40 + m_Alignment: 0 + m_AlignByGeometry: 0 + m_RichText: 0 + m_HorizontalOverflow: 1 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: +--- !u!222 &577879794 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 577879791} + m_CullTransparentMesh: 1 +--- !u!1 &938304843 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 938304844} + - component: {fileID: 938304846} + - component: {fileID: 938304845} + m_Layer: 5 + m_Name: Handle + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &938304844 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 938304843} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1705617157} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 20, y: 20} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &938304845 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 938304843} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &938304846 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 938304843} + m_CullTransparentMesh: 1 +--- !u!1 &1118021351 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1118021355} + - component: {fileID: 1118021354} + - component: {fileID: 1118021353} + - component: {fileID: 1118021352} + m_Layer: 5 + m_Name: Initial Load Screen Canvas + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1118021352 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1118021351} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreReversedGraphics: 1 + m_BlockingObjects: 0 + m_BlockingMask: + serializedVersion: 2 + m_Bits: 4294967295 +--- !u!114 &1118021353 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1118021351} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UiScaleMode: 0 + m_ReferencePixelsPerUnit: 100 + m_ScaleFactor: 1 + m_ReferenceResolution: {x: 800, y: 600} + m_ScreenMatchMode: 0 + m_MatchWidthOrHeight: 0 + m_PhysicalUnit: 3 + m_FallbackScreenDPI: 96 + m_DefaultSpriteDPI: 96 + m_DynamicPixelsPerUnit: 1 + m_PresetInfoIsWorld: 0 +--- !u!223 &1118021354 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1118021351} + m_Enabled: 1 + serializedVersion: 3 + m_RenderMode: 0 + m_Camera: {fileID: 0} + m_PlaneDistance: 100 + m_PixelPerfect: 1 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_AdditionalShaderChannelsFlag: 0 + m_SortingLayerID: 0 + m_SortingOrder: 1 + m_TargetDisplay: 0 +--- !u!224 &1118021355 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1118021351} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0, y: 0, z: 0} + m_Children: + - {fileID: 19247259} + - {fileID: 1690878378} + - {fileID: 1334026408} + m_Father: {fileID: 0} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0, y: 0} +--- !u!1 &1334026407 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1334026408} + - component: {fileID: 1334026410} + - component: {fileID: 1334026409} + - component: {fileID: 1334026411} + m_Layer: 5 + m_Name: Initial Load Screen Logo + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1334026408 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1334026407} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1118021355} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 1024, y: 768} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1334026409 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1334026407} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1344c3c82d62a2a41a3576d8abb8e3ea, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Texture: {fileID: 0} + m_UVRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 +--- !u!222 &1334026410 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1334026407} + m_CullTransparentMesh: 1 +--- !u!114 &1334026411 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1334026407} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 68f59c2b02ecd40468c22f3eb960d4bd, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &1339770443 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1339770444} + - component: {fileID: 1339770447} + m_Layer: 5 + m_Name: Viewport + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1339770444 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1339770443} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 2060532664} + m_Father: {fileID: 6315364} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: -17, y: 0} + m_Pivot: {x: 0, y: 1} +--- !u!222 &1339770447 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1339770443} + m_CullTransparentMesh: 1 +--- !u!1 &1383294978 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1383294979} + - component: {fileID: 1383294982} + - component: {fileID: 1383294981} + - component: {fileID: 1383294980} + m_Layer: 5 + m_Name: ConsolePanel + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1383294979 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1383294978} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 6315364} + - {fileID: 2001754371} + m_Father: {fileID: 30129051} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -99.20001} + m_SizeDelta: {x: 0, y: 198.4} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1383294980 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1383294978} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 31a19414c41e5ae4aae2af33fee712f6, type: 3} + m_Name: + m_EditorClassIdentifier: + m_ShowMaskGraphic: 1 +--- !u!114 &1383294981 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1383294978} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1383294982 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1383294978} + m_CullTransparentMesh: 1 +--- !u!1 &1442540124 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1442540125} + m_Layer: 0 + m_Name: Scene + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1442540125 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1442540124} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 465.13177, y: 296.14844, z: -140.0398} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1584831904} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1496761001 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1496761002} + - component: {fileID: 1496761004} + - component: {fileID: 1496761003} + m_Layer: 5 + m_Name: Placeholder + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1496761002 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1496761001} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 238388069} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -0.5} + m_SizeDelta: {x: -20, y: -13} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1496761003 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1496761001} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 0.5} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 14 + m_FontStyle: 2 + m_BestFit: 0 + m_MinSize: 10 + m_MaxSize: 40 + m_Alignment: 0 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: +--- !u!222 &1496761004 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1496761001} + m_CullTransparentMesh: 1 +--- !u!1 &1584831903 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1584831904} + - component: {fileID: 1584831905} + m_Layer: 0 + m_Name: Main Menu Controller + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1584831904 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1584831903} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1442540125} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1584831905 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1584831903} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 71cec8867c0a85541a6e9755728c38a7, type: 3} + m_Name: + m_EditorClassIdentifier: + FadeOutTime: 0.5 + InitialLoadScreenBackgroundImage: {fileID: 19247262} + InitialLoadScreenLogoImage: {fileID: 1334026411} + InitialLoadScreenReiaPlayer: {fileID: 1690878381} +--- !u!1 &1690878377 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1690878378} + - component: {fileID: 1690878380} + - component: {fileID: 1690878379} + - component: {fileID: 1690878381} + m_Layer: 5 + m_Name: Initial Load Animation + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1690878378 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1690878377} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: -1, z: 1} + m_Children: [] + m_Father: {fileID: 1118021355} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 800, y: 600} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1690878379 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1690878377} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1344c3c82d62a2a41a3576d8abb8e3ea, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Texture: {fileID: 0} + m_UVRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 +--- !u!222 &1690878380 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1690878377} + m_CullTransparentMesh: 1 +--- !u!114 &1690878381 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1690878377} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 270428b48761b614c808c1e4a66f188d, type: 3} + m_Name: + m_EditorClassIdentifier: + Speed: 0 +--- !u!1 &1705617156 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1705617157} + m_Layer: 5 + m_Name: Sliding Area + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1705617157 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1705617156} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 938304844} + m_Father: {fileID: 2001754371} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: -20, y: -20} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &1755469743 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1755469747} + - component: {fileID: 1755469746} + - component: {fileID: 1755469745} + - component: {fileID: 1755469744} + - component: {fileID: 1755469748} + m_Layer: 5 + m_Name: Canvas + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1755469744 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1755469743} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreReversedGraphics: 1 + m_BlockingObjects: 0 + m_BlockingMask: + serializedVersion: 2 + m_Bits: 4294967295 +--- !u!114 &1755469745 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1755469743} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UiScaleMode: 0 + m_ReferencePixelsPerUnit: 100 + m_ScaleFactor: 1 + m_ReferenceResolution: {x: 800, y: 600} + m_ScreenMatchMode: 0 + m_MatchWidthOrHeight: 0 + m_PhysicalUnit: 3 + m_FallbackScreenDPI: 96 + m_DefaultSpriteDPI: 96 + m_DynamicPixelsPerUnit: 1 + m_PresetInfoIsWorld: 0 +--- !u!223 &1755469746 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1755469743} + m_Enabled: 1 + serializedVersion: 3 + m_RenderMode: 0 + m_Camera: {fileID: 0} + m_PlaneDistance: 100 + m_PixelPerfect: 1 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_AdditionalShaderChannelsFlag: 0 + m_SortingLayerID: 0 + m_SortingOrder: 0 + m_TargetDisplay: 0 +--- !u!224 &1755469747 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1755469743} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0, y: 0, z: 0} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0, y: 0} +--- !u!114 &1755469748 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1755469743} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: db3b6e6445c9df84bb2e95b9365382be, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &1836641136 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1836641139} + - component: {fileID: 1836641138} + - component: {fileID: 1836641137} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!81 &1836641137 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1836641136} + m_Enabled: 1 +--- !u!20 &1836641138 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1836641136} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 2 + m_BackGroundColor: {r: 0.003921569, g: 0.13725491, b: 0.24313726, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 10 + far clip plane: 2000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &1836641139 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1836641136} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &2001754370 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2001754371} + - component: {fileID: 2001754374} + - component: {fileID: 2001754373} + - component: {fileID: 2001754372} + m_Layer: 5 + m_Name: Scrollbar Vertical + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2001754371 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2001754370} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1705617157} + m_Father: {fileID: 1383294979} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0.000015258789} + m_SizeDelta: {x: 20, y: 0} + m_Pivot: {x: 1, y: 1} +--- !u!114 &2001754372 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2001754370} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2a4db7a114972834c8e4117be1d82ba3, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 938304845} + m_HandleRect: {fileID: 938304844} + m_Direction: 2 + m_Value: 0 + m_Size: 1 + m_NumberOfSteps: 0 + m_OnValueChanged: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &2001754373 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2001754370} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &2001754374 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2001754370} + m_CullTransparentMesh: 1 +--- !u!1 &2060532661 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2060532664} + - component: {fileID: 2060532663} + - component: {fileID: 2060532662} + - component: {fileID: 2060532665} + m_Layer: 5 + m_Name: Console Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &2060532662 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2060532661} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 14 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 10 + m_MaxSize: 40 + m_Alignment: 0 + m_AlignByGeometry: 0 + m_RichText: 0 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: +--- !u!222 &2060532663 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2060532661} + m_CullTransparentMesh: 1 +--- !u!224 &2060532664 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2060532661} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1339770444} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0, y: 1} +--- !u!114 &2060532665 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2060532661} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3245ec927659c4140ac4f8d17403cc18, type: 3} + m_Name: + m_EditorClassIdentifier: + m_HorizontalFit: 0 + m_VerticalFit: 2 diff --git a/Assets/Scenes/Main Menu.unity.meta b/Assets/Scenes/Main Menu.unity.meta new file mode 100644 index 00000000..ec5f74eb --- /dev/null +++ b/Assets/Scenes/Main Menu.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: b8799d538c243b245a875e084cdcd466 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scenes/Neighborhood.unity b/Assets/Scenes/Neighborhood.unity index e2598f50..a164fd06 100644 --- a/Assets/Scenes/Neighborhood.unity +++ b/Assets/Scenes/Neighborhood.unity @@ -302,51 +302,6 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: e110dc8964f72d54e82c846c2a6a37c8, type: 3} m_Name: m_EditorClassIdentifier: ---- !u!1 &641803311 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 641803313} - - component: {fileID: 641803312} - m_Layer: 0 - m_Name: Neighborhood Simulation - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &641803312 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 641803311} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 695349b682404ab4281ad85c1612b41d, type: 3} - m_Name: - m_EditorClassIdentifier: - SimulationContext: 2 - TickRate: 20 ---- !u!4 &641803313 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 641803311} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 384.94568, y: 523.42, z: 24.198853} - m_LocalScale: {x: 1, y: 1, z: 1} - m_Children: [] - m_Father: {fileID: 0} - m_RootOrder: 8 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &779771439 GameObject: m_ObjectHideFlags: 0 @@ -359,7 +314,7 @@ GameObject: - component: {fileID: 779771442} - component: {fileID: 779771441} - component: {fileID: 779771444} - m_Layer: 0 + m_Layer: 6 m_Name: Water m_TagString: Untagged m_Icon: {fileID: 0} diff --git a/Assets/Scenes/Startup.unity b/Assets/Scenes/Startup.unity index feafcc97..031cfa8e 100644 --- a/Assets/Scenes/Startup.unity +++ b/Assets/Scenes/Startup.unity @@ -38,7 +38,7 @@ RenderSettings: m_ReflectionIntensity: 1 m_CustomReflection: {fileID: 0} m_Sun: {fileID: 0} - m_IndirectSpecularColor: {r: 0.44657898, g: 0.4964133, b: 0.5748178, a: 1} + m_IndirectSpecularColor: {r: 0.37311953, g: 0.38074014, b: 0.3587274, a: 1} m_UseRadianceAmbientProbe: 0 --- !u!157 &3 LightmapSettings: @@ -123,1798 +123,7 @@ NavMeshSettings: debug: m_Flags: 0 m_NavMeshData: {fileID: 0} ---- !u!1 &6315363 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 6315364} - - component: {fileID: 6315367} - - component: {fileID: 6315365} - m_Layer: 5 - m_Name: Scroll View - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!224 &6315364 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 6315363} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_Children: - - {fileID: 1339770444} - m_Father: {fileID: 1383294979} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 1} - m_AnchorMax: {x: 1, y: 1} - m_AnchoredPosition: {x: 1.6949463, y: -105.1} - m_SizeDelta: {x: -3.3900743, y: 200} - m_Pivot: {x: 0.5, y: 0.5} ---- !u!114 &6315365 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 6315363} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 1aa08ab6e0800fa44ae55d278d1423e3, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Content: {fileID: 2060532664} - m_Horizontal: 0 - m_Vertical: 1 - m_MovementType: 2 - m_Elasticity: 0.1 - m_Inertia: 0 - m_DecelerationRate: 0.135 - m_ScrollSensitivity: 40 - m_Viewport: {fileID: 1339770444} - m_HorizontalScrollbar: {fileID: 0} - m_VerticalScrollbar: {fileID: 2001754372} - m_HorizontalScrollbarVisibility: 2 - m_VerticalScrollbarVisibility: 1 - m_HorizontalScrollbarSpacing: -3 - m_VerticalScrollbarSpacing: -3 - m_OnValueChanged: - m_PersistentCalls: - m_Calls: [] ---- !u!222 &6315367 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 6315363} - m_CullTransparentMesh: 1 ---- !u!1 &19247258 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 19247259} - - component: {fileID: 19247261} - - component: {fileID: 19247260} - - component: {fileID: 19247262} - m_Layer: 5 - m_Name: Initial Load Screen Background - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!224 &19247259 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 19247258} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_Children: [] - m_Father: {fileID: 1118021355} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0.5, y: 0.5} - m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 1024, y: 768} - m_Pivot: {x: 0.5, y: 0.5} ---- !u!114 &19247260 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 19247258} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 1344c3c82d62a2a41a3576d8abb8e3ea, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_Texture: {fileID: 0} - m_UVRect: - serializedVersion: 2 - x: 0 - y: 0 - width: 1 - height: 1 ---- !u!222 &19247261 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 19247258} - m_CullTransparentMesh: 1 ---- !u!114 &19247262 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 19247258} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 68f59c2b02ecd40468c22f3eb960d4bd, type: 3} - m_Name: - m_EditorClassIdentifier: ---- !u!1 &30129050 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 30129051} - m_Layer: 5 - m_Name: Cheat Console - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!224 &30129051 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 30129050} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_Children: - - {fileID: 238388069} - - {fileID: 1383294979} - m_Father: {fileID: 188582820} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 1, y: 1} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 0, y: 0} - m_Pivot: {x: 0.5, y: 0.5} ---- !u!1 &188582815 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 188582820} - - component: {fileID: 188582819} - - component: {fileID: 188582818} - - component: {fileID: 188582817} - - component: {fileID: 188582816} - m_Layer: 5 - m_Name: Cheat Console Canvas - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &188582816 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 188582815} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: c7d73af69c9e8614080ca76faff3ae13, type: 3} - m_Name: - m_EditorClassIdentifier: - ConsoleParent: {fileID: 30129050} - CheatInputField: {fileID: 238388070} - ConsoleOutput: {fileID: 2060532662} - ConsoleScroll: {fileID: 6315365} ---- !u!114 &188582817 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 188582815} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3} - m_Name: - m_EditorClassIdentifier: - m_IgnoreReversedGraphics: 1 - m_BlockingObjects: 0 - m_BlockingMask: - serializedVersion: 2 - m_Bits: 4294967295 ---- !u!114 &188582818 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 188582815} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UiScaleMode: 0 - m_ReferencePixelsPerUnit: 100 - m_ScaleFactor: 1 - m_ReferenceResolution: {x: 800, y: 600} - m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0 - m_PhysicalUnit: 3 - m_FallbackScreenDPI: 96 - m_DefaultSpriteDPI: 96 - m_DynamicPixelsPerUnit: 1 - m_PresetInfoIsWorld: 0 ---- !u!223 &188582819 -Canvas: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 188582815} - m_Enabled: 1 - serializedVersion: 3 - m_RenderMode: 0 - m_Camera: {fileID: 0} - m_PlaneDistance: 100 - m_PixelPerfect: 0 - m_ReceivesEvents: 1 - m_OverrideSorting: 0 - m_OverridePixelPerfect: 0 - m_SortingBucketNormalizedSize: 0 - m_AdditionalShaderChannelsFlag: 0 - m_SortingLayerID: 0 - m_SortingOrder: 100 - m_TargetDisplay: 0 ---- !u!224 &188582820 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 188582815} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 0, y: 0, z: 0} - m_Children: - - {fileID: 30129051} - m_Father: {fileID: 0} - m_RootOrder: 7 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 0, y: 0} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 0, y: 0} - m_Pivot: {x: 0, y: 0} ---- !u!1 &238388068 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 238388069} - - component: {fileID: 238388072} - - component: {fileID: 238388071} - - component: {fileID: 238388070} - m_Layer: 5 - m_Name: InputField - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!224 &238388069 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 238388068} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_Children: - - {fileID: 1496761002} - - {fileID: 577879792} - m_Father: {fileID: 30129051} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 1} - m_AnchorMax: {x: 1, y: 1} - m_AnchoredPosition: {x: 0, y: -213.4} - m_SizeDelta: {x: 0, y: 30} - m_Pivot: {x: 0.5, y: 0.5} ---- !u!114 &238388070 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 238388068} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: d199490a83bb2b844b9695cbf13b01ef, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Navigation: - m_Mode: 3 - m_WrapAround: 0 - m_SelectOnUp: {fileID: 0} - m_SelectOnDown: {fileID: 0} - m_SelectOnLeft: {fileID: 0} - m_SelectOnRight: {fileID: 0} - m_Transition: 1 - m_Colors: - m_NormalColor: {r: 1, g: 1, b: 1, a: 1} - m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} - m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} - m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} - m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} - m_ColorMultiplier: 1 - m_FadeDuration: 0.1 - m_SpriteState: - m_HighlightedSprite: {fileID: 0} - m_PressedSprite: {fileID: 0} - m_SelectedSprite: {fileID: 0} - m_DisabledSprite: {fileID: 0} - m_AnimationTriggers: - m_NormalTrigger: Normal - m_HighlightedTrigger: Highlighted - m_PressedTrigger: Pressed - m_SelectedTrigger: Selected - m_DisabledTrigger: Disabled - m_Interactable: 1 - m_TargetGraphic: {fileID: 238388071} - m_TextComponent: {fileID: 577879793} - m_Placeholder: {fileID: 1496761003} - m_ContentType: 0 - m_InputType: 0 - m_AsteriskChar: 42 - m_KeyboardType: 0 - m_LineType: 0 - m_HideMobileInput: 0 - m_CharacterValidation: 0 - m_CharacterLimit: 0 - m_OnEndEdit: - m_PersistentCalls: - m_Calls: [] - m_OnValueChanged: - m_PersistentCalls: - m_Calls: [] - m_CaretColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} - m_CustomCaretColor: 0 - m_SelectionColor: {r: 0.65882355, g: 0.80784315, b: 1, a: 0.7529412} - m_Text: - m_CaretBlinkRate: 0.85 - m_CaretWidth: 1 - m_ReadOnly: 0 - m_ShouldActivateOnSelect: 1 ---- !u!114 &238388071 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 238388068} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_Sprite: {fileID: 10911, guid: 0000000000000000f000000000000000, type: 0} - m_Type: 1 - m_PreserveAspect: 0 - m_FillCenter: 1 - m_FillMethod: 4 - m_FillAmount: 1 - m_FillClockwise: 1 - m_FillOrigin: 0 - m_UseSpriteMesh: 0 - m_PixelsPerUnitMultiplier: 1 ---- !u!222 &238388072 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 238388068} - m_CullTransparentMesh: 1 ---- !u!1 &322359566 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 322359568} - - component: {fileID: 322359567} - m_Layer: 0 - m_Name: Directional Light - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!108 &322359567 -Light: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 322359566} - m_Enabled: 1 - serializedVersion: 10 - m_Type: 1 - m_Shape: 0 - m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} - m_Intensity: 1 - m_Range: 10 - m_SpotAngle: 30 - m_InnerSpotAngle: 21.80208 - m_CookieSize: 10 - m_Shadows: - m_Type: 2 - m_Resolution: -1 - m_CustomResolution: -1 - m_Strength: 1 - m_Bias: 0.05 - m_NormalBias: 0.4 - m_NearPlane: 0.2 - m_CullingMatrixOverride: - e00: 1 - e01: 0 - e02: 0 - e03: 0 - e10: 0 - e11: 1 - e12: 0 - e13: 0 - e20: 0 - e21: 0 - e22: 1 - e23: 0 - e30: 0 - e31: 0 - e32: 0 - e33: 1 - m_UseCullingMatrixOverride: 0 - m_Cookie: {fileID: 0} - m_DrawHalo: 0 - m_Flare: {fileID: 0} - m_RenderMode: 0 - m_CullingMask: - serializedVersion: 2 - m_Bits: 4294967295 - m_RenderingLayerMask: 1 - m_Lightmapping: 4 - m_LightShadowCasterMode: 0 - m_AreaSize: {x: 1, y: 1} - m_BounceIntensity: 1 - m_ColorTemperature: 6570 - m_UseColorTemperature: 0 - m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} - m_UseBoundingSphereOverride: 0 - m_UseViewFrustumForShadowCasterCull: 1 - m_ShadowRadius: 0 - m_ShadowAngle: 0 ---- !u!4 &322359568 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 322359566} - m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} - m_LocalPosition: {x: 0, y: 3, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_Children: [] - m_Father: {fileID: 0} - m_RootOrder: 3 - m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} ---- !u!1 &431621066 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 431621069} - - component: {fileID: 431621068} - - component: {fileID: 431621067} - m_Layer: 0 - m_Name: EventSystem - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &431621067 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 431621066} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3} - m_Name: - m_EditorClassIdentifier: - m_HorizontalAxis: Horizontal - m_VerticalAxis: Vertical - m_SubmitButton: Submit - m_CancelButton: Cancel - m_InputActionsPerSecond: 10 - m_RepeatDelay: 0.5 - m_ForceModuleActive: 0 ---- !u!114 &431621068 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 431621066} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3} - m_Name: - m_EditorClassIdentifier: - m_FirstSelected: {fileID: 0} - m_sendNavigationEvents: 1 - m_DragThreshold: 10 ---- !u!4 &431621069 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 431621066} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_Children: [] - m_Father: {fileID: 0} - m_RootOrder: 6 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &577879791 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 577879792} - - component: {fileID: 577879794} - - component: {fileID: 577879793} - m_Layer: 5 - m_Name: Text - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!224 &577879792 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 577879791} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_Children: [] - m_Father: {fileID: 238388069} - m_RootOrder: 1 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 1, y: 1} - m_AnchoredPosition: {x: 0, y: -0.5} - m_SizeDelta: {x: -20, y: -13} - m_Pivot: {x: 0.5, y: 0.5} ---- !u!114 &577879793 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 577879791} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_FontData: - m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} - m_FontSize: 14 - m_FontStyle: 0 - m_BestFit: 0 - m_MinSize: 10 - m_MaxSize: 40 - m_Alignment: 0 - m_AlignByGeometry: 0 - m_RichText: 0 - m_HorizontalOverflow: 1 - m_VerticalOverflow: 0 - m_LineSpacing: 1 - m_Text: ---- !u!222 &577879794 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 577879791} - m_CullTransparentMesh: 1 ---- !u!1 &938304843 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 938304844} - - component: {fileID: 938304846} - - component: {fileID: 938304845} - m_Layer: 5 - m_Name: Handle - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!224 &938304844 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 938304843} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_Children: [] - m_Father: {fileID: 1705617157} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 0, y: 0} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 20, y: 20} - m_Pivot: {x: 0.5, y: 0.5} ---- !u!114 &938304845 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 938304843} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} - m_Type: 1 - m_PreserveAspect: 0 - m_FillCenter: 1 - m_FillMethod: 4 - m_FillAmount: 1 - m_FillClockwise: 1 - m_FillOrigin: 0 - m_UseSpriteMesh: 0 - m_PixelsPerUnitMultiplier: 1 ---- !u!222 &938304846 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 938304843} - m_CullTransparentMesh: 1 ---- !u!1 &1118021351 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1118021355} - - component: {fileID: 1118021354} - - component: {fileID: 1118021353} - - component: {fileID: 1118021352} - m_Layer: 5 - m_Name: Initial Load Screen Canvas - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &1118021352 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1118021351} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3} - m_Name: - m_EditorClassIdentifier: - m_IgnoreReversedGraphics: 1 - m_BlockingObjects: 0 - m_BlockingMask: - serializedVersion: 2 - m_Bits: 4294967295 ---- !u!114 &1118021353 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1118021351} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UiScaleMode: 0 - m_ReferencePixelsPerUnit: 100 - m_ScaleFactor: 1 - m_ReferenceResolution: {x: 800, y: 600} - m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0 - m_PhysicalUnit: 3 - m_FallbackScreenDPI: 96 - m_DefaultSpriteDPI: 96 - m_DynamicPixelsPerUnit: 1 - m_PresetInfoIsWorld: 0 ---- !u!223 &1118021354 -Canvas: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1118021351} - m_Enabled: 1 - serializedVersion: 3 - m_RenderMode: 0 - m_Camera: {fileID: 0} - m_PlaneDistance: 100 - m_PixelPerfect: 1 - m_ReceivesEvents: 1 - m_OverrideSorting: 0 - m_OverridePixelPerfect: 0 - m_SortingBucketNormalizedSize: 0 - m_AdditionalShaderChannelsFlag: 0 - m_SortingLayerID: 0 - m_SortingOrder: 1 - m_TargetDisplay: 0 ---- !u!224 &1118021355 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1118021351} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 0, y: 0, z: 0} - m_Children: - - {fileID: 19247259} - - {fileID: 1690878378} - - {fileID: 1334026408} - m_Father: {fileID: 0} - m_RootOrder: 5 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 0, y: 0} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 0, y: 0} - m_Pivot: {x: 0, y: 0} ---- !u!1 &1334026407 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1334026408} - - component: {fileID: 1334026410} - - component: {fileID: 1334026409} - - component: {fileID: 1334026411} - m_Layer: 5 - m_Name: Initial Load Screen Logo - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!224 &1334026408 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1334026407} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_Children: [] - m_Father: {fileID: 1118021355} - m_RootOrder: 2 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0.5, y: 0.5} - m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 1024, y: 768} - m_Pivot: {x: 0.5, y: 0.5} ---- !u!114 &1334026409 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1334026407} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 1344c3c82d62a2a41a3576d8abb8e3ea, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_Texture: {fileID: 0} - m_UVRect: - serializedVersion: 2 - x: 0 - y: 0 - width: 1 - height: 1 ---- !u!222 &1334026410 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1334026407} - m_CullTransparentMesh: 1 ---- !u!114 &1334026411 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1334026407} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 68f59c2b02ecd40468c22f3eb960d4bd, type: 3} - m_Name: - m_EditorClassIdentifier: ---- !u!1 &1339770443 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1339770444} - - component: {fileID: 1339770447} - m_Layer: 5 - m_Name: Viewport - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!224 &1339770444 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1339770443} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_Children: - - {fileID: 2060532664} - m_Father: {fileID: 6315364} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 1, y: 1} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: -17, y: 0} - m_Pivot: {x: 0, y: 1} ---- !u!222 &1339770447 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1339770443} - m_CullTransparentMesh: 1 ---- !u!1 &1383294978 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1383294979} - - component: {fileID: 1383294982} - - component: {fileID: 1383294981} - - component: {fileID: 1383294980} - m_Layer: 5 - m_Name: ConsolePanel - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!224 &1383294979 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1383294978} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_Children: - - {fileID: 6315364} - - {fileID: 2001754371} - m_Father: {fileID: 30129051} - m_RootOrder: 1 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 1} - m_AnchorMax: {x: 1, y: 1} - m_AnchoredPosition: {x: 0, y: -99.20001} - m_SizeDelta: {x: 0, y: 198.4} - m_Pivot: {x: 0.5, y: 0.5} ---- !u!114 &1383294980 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1383294978} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 31a19414c41e5ae4aae2af33fee712f6, type: 3} - m_Name: - m_EditorClassIdentifier: - m_ShowMaskGraphic: 1 ---- !u!114 &1383294981 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1383294978} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} - m_Type: 1 - m_PreserveAspect: 0 - m_FillCenter: 1 - m_FillMethod: 4 - m_FillAmount: 1 - m_FillClockwise: 1 - m_FillOrigin: 0 - m_UseSpriteMesh: 0 - m_PixelsPerUnitMultiplier: 1 ---- !u!222 &1383294982 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1383294978} - m_CullTransparentMesh: 1 ---- !u!1 &1442540124 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1442540125} - m_Layer: 0 - m_Name: Scene - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &1442540125 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1442540124} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 465.13177, y: 296.14844, z: -140.0398} - m_LocalScale: {x: 1, y: 1, z: 1} - m_Children: - - {fileID: 1584831904} - m_Father: {fileID: 0} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &1496761001 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1496761002} - - component: {fileID: 1496761004} - - component: {fileID: 1496761003} - m_Layer: 5 - m_Name: Placeholder - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!224 &1496761002 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1496761001} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_Children: [] - m_Father: {fileID: 238388069} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 1, y: 1} - m_AnchoredPosition: {x: 0, y: -0.5} - m_SizeDelta: {x: -20, y: -13} - m_Pivot: {x: 0.5, y: 0.5} ---- !u!114 &1496761003 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1496761001} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 0.5} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_FontData: - m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} - m_FontSize: 14 - m_FontStyle: 2 - m_BestFit: 0 - m_MinSize: 10 - m_MaxSize: 40 - m_Alignment: 0 - m_AlignByGeometry: 0 - m_RichText: 1 - m_HorizontalOverflow: 0 - m_VerticalOverflow: 0 - m_LineSpacing: 1 - m_Text: ---- !u!222 &1496761004 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1496761001} - m_CullTransparentMesh: 1 ---- !u!1 &1584831903 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1584831904} - - component: {fileID: 1584831905} - m_Layer: 0 - m_Name: Startup Controller - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &1584831904 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1584831903} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_Children: [] - m_Father: {fileID: 1442540125} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!114 &1584831905 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1584831903} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 71cec8867c0a85541a6e9755728c38a7, type: 3} - m_Name: - m_EditorClassIdentifier: - FadeOutTime: 0.5 - InitialLoadScreenBackgroundImage: {fileID: 19247262} - InitialLoadScreenLogoImage: {fileID: 1334026411} - InitialLoadScreenReiaPlayer: {fileID: 1690878381} - EnableReia: 1 - LoadObjects: 1 - StreamReia: 1 ---- !u!1 &1690878377 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1690878378} - - component: {fileID: 1690878380} - - component: {fileID: 1690878379} - - component: {fileID: 1690878381} - m_Layer: 5 - m_Name: Initial Load Animation - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!224 &1690878378 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1690878377} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: -1, z: 1} - m_Children: [] - m_Father: {fileID: 1118021355} - m_RootOrder: 1 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0.5, y: 0.5} - m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 800, y: 600} - m_Pivot: {x: 0.5, y: 0.5} ---- !u!114 &1690878379 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1690878377} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 1344c3c82d62a2a41a3576d8abb8e3ea, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_Texture: {fileID: 0} - m_UVRect: - serializedVersion: 2 - x: 0 - y: 0 - width: 1 - height: 1 ---- !u!222 &1690878380 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1690878377} - m_CullTransparentMesh: 1 ---- !u!114 &1690878381 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1690878377} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 270428b48761b614c808c1e4a66f188d, type: 3} - m_Name: - m_EditorClassIdentifier: - Speed: 0 ---- !u!1 &1705617156 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1705617157} - m_Layer: 5 - m_Name: Sliding Area - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!224 &1705617157 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1705617156} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_Children: - - {fileID: 938304844} - m_Father: {fileID: 2001754371} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 1, y: 1} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: -20, y: -20} - m_Pivot: {x: 0.5, y: 0.5} ---- !u!1 &1755469743 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1755469747} - - component: {fileID: 1755469746} - - component: {fileID: 1755469745} - - component: {fileID: 1755469744} - - component: {fileID: 1755469748} - m_Layer: 5 - m_Name: Canvas - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &1755469744 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1755469743} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3} - m_Name: - m_EditorClassIdentifier: - m_IgnoreReversedGraphics: 1 - m_BlockingObjects: 0 - m_BlockingMask: - serializedVersion: 2 - m_Bits: 4294967295 ---- !u!114 &1755469745 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1755469743} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UiScaleMode: 0 - m_ReferencePixelsPerUnit: 100 - m_ScaleFactor: 1 - m_ReferenceResolution: {x: 800, y: 600} - m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0 - m_PhysicalUnit: 3 - m_FallbackScreenDPI: 96 - m_DefaultSpriteDPI: 96 - m_DynamicPixelsPerUnit: 1 - m_PresetInfoIsWorld: 0 ---- !u!223 &1755469746 -Canvas: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1755469743} - m_Enabled: 1 - serializedVersion: 3 - m_RenderMode: 0 - m_Camera: {fileID: 0} - m_PlaneDistance: 100 - m_PixelPerfect: 1 - m_ReceivesEvents: 1 - m_OverrideSorting: 0 - m_OverridePixelPerfect: 0 - m_SortingBucketNormalizedSize: 0 - m_AdditionalShaderChannelsFlag: 0 - m_SortingLayerID: 0 - m_SortingOrder: 0 - m_TargetDisplay: 0 ---- !u!224 &1755469747 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1755469743} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 0, y: 0, z: 0} - m_Children: [] - m_Father: {fileID: 0} - m_RootOrder: 4 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 0, y: 0} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 0, y: 0} - m_Pivot: {x: 0, y: 0} ---- !u!114 &1755469748 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1755469743} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: db3b6e6445c9df84bb2e95b9365382be, type: 3} - m_Name: - m_EditorClassIdentifier: ---- !u!1 &1836641136 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1836641139} - - component: {fileID: 1836641138} - - component: {fileID: 1836641137} - m_Layer: 0 - m_Name: Main Camera - m_TagString: MainCamera - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!81 &1836641137 -AudioListener: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1836641136} - m_Enabled: 1 ---- !u!20 &1836641138 -Camera: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1836641136} - m_Enabled: 1 - serializedVersion: 2 - m_ClearFlags: 2 - m_BackGroundColor: {r: 0.003921569, g: 0.13725491, b: 0.24313726, a: 0} - m_projectionMatrixMode: 1 - m_GateFitMode: 2 - m_FOVAxisMode: 0 - m_SensorSize: {x: 36, y: 24} - m_LensShift: {x: 0, y: 0} - m_FocalLength: 50 - m_NormalizedViewPortRect: - serializedVersion: 2 - x: 0 - y: 0 - width: 1 - height: 1 - near clip plane: 10 - far clip plane: 2000 - field of view: 60 - orthographic: 0 - orthographic size: 5 - m_Depth: -1 - m_CullingMask: - serializedVersion: 2 - m_Bits: 4294967295 - m_RenderingPath: -1 - m_TargetTexture: {fileID: 0} - m_TargetDisplay: 0 - m_TargetEye: 3 - m_HDR: 1 - m_AllowMSAA: 1 - m_AllowDynamicResolution: 0 - m_ForceIntoRT: 0 - m_OcclusionCulling: 1 - m_StereoConvergence: 10 - m_StereoSeparation: 0.022 ---- !u!4 &1836641139 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1836641136} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 1, z: -10} - m_LocalScale: {x: 1, y: 1, z: 1} - m_Children: [] - m_Father: {fileID: 0} - m_RootOrder: 2 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &2001754370 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 2001754371} - - component: {fileID: 2001754374} - - component: {fileID: 2001754373} - - component: {fileID: 2001754372} - m_Layer: 5 - m_Name: Scrollbar Vertical - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!224 &2001754371 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 2001754370} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_Children: - - {fileID: 1705617157} - m_Father: {fileID: 1383294979} - m_RootOrder: 1 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 1, y: 0} - m_AnchorMax: {x: 1, y: 1} - m_AnchoredPosition: {x: 0, y: 0.000015258789} - m_SizeDelta: {x: 20, y: 0} - m_Pivot: {x: 1, y: 1} ---- !u!114 &2001754372 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 2001754370} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 2a4db7a114972834c8e4117be1d82ba3, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Navigation: - m_Mode: 3 - m_WrapAround: 0 - m_SelectOnUp: {fileID: 0} - m_SelectOnDown: {fileID: 0} - m_SelectOnLeft: {fileID: 0} - m_SelectOnRight: {fileID: 0} - m_Transition: 1 - m_Colors: - m_NormalColor: {r: 1, g: 1, b: 1, a: 1} - m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} - m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} - m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} - m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} - m_ColorMultiplier: 1 - m_FadeDuration: 0.1 - m_SpriteState: - m_HighlightedSprite: {fileID: 0} - m_PressedSprite: {fileID: 0} - m_SelectedSprite: {fileID: 0} - m_DisabledSprite: {fileID: 0} - m_AnimationTriggers: - m_NormalTrigger: Normal - m_HighlightedTrigger: Highlighted - m_PressedTrigger: Pressed - m_SelectedTrigger: Selected - m_DisabledTrigger: Disabled - m_Interactable: 1 - m_TargetGraphic: {fileID: 938304845} - m_HandleRect: {fileID: 938304844} - m_Direction: 2 - m_Value: 0 - m_Size: 1 - m_NumberOfSteps: 0 - m_OnValueChanged: - m_PersistentCalls: - m_Calls: [] ---- !u!114 &2001754373 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 2001754370} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} - m_Type: 1 - m_PreserveAspect: 0 - m_FillCenter: 1 - m_FillMethod: 4 - m_FillAmount: 1 - m_FillClockwise: 1 - m_FillOrigin: 0 - m_UseSpriteMesh: 0 - m_PixelsPerUnitMultiplier: 1 ---- !u!222 &2001754374 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 2001754370} - m_CullTransparentMesh: 1 ---- !u!1 &2060532661 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 2060532664} - - component: {fileID: 2060532663} - - component: {fileID: 2060532662} - - component: {fileID: 2060532665} - m_Layer: 5 - m_Name: Console Text - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &2060532662 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 2060532661} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_FontData: - m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} - m_FontSize: 14 - m_FontStyle: 0 - m_BestFit: 0 - m_MinSize: 10 - m_MaxSize: 40 - m_Alignment: 0 - m_AlignByGeometry: 0 - m_RichText: 0 - m_HorizontalOverflow: 0 - m_VerticalOverflow: 0 - m_LineSpacing: 1 - m_Text: ---- !u!222 &2060532663 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 2060532661} - m_CullTransparentMesh: 1 ---- !u!224 &2060532664 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 2060532661} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_Children: [] - m_Father: {fileID: 1339770444} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 1, y: 1} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 0, y: 0} - m_Pivot: {x: 0, y: 1} ---- !u!114 &2060532665 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 2060532661} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 3245ec927659c4140ac4f8d17403cc18, type: 3} - m_Name: - m_EditorClassIdentifier: - m_HorizontalFit: 0 - m_VerticalFit: 2 ---- !u!1001 &2118235053 +--- !u!1001 &867213080 PrefabInstance: m_ObjectHideFlags: 0 serializedVersion: 2 @@ -1923,11 +132,11 @@ PrefabInstance: m_Modifications: - target: {fileID: 2467515431058217605, guid: 188047b711783b74aa73c17ff9d66147, type: 3} propertyPath: m_Name - value: Scene Startup + value: Startup objectReference: {fileID: 0} - target: {fileID: 2467515431058217606, guid: 188047b711783b74aa73c17ff9d66147, type: 3} propertyPath: m_RootOrder - value: 1 + value: 0 objectReference: {fileID: 0} - target: {fileID: 2467515431058217606, guid: 188047b711783b74aa73c17ff9d66147, type: 3} propertyPath: m_LocalPosition.x diff --git a/Assets/Scenes/Startup.unity.meta b/Assets/Scenes/Startup.unity.meta index ec5f74eb..bd08bed7 100644 --- a/Assets/Scenes/Startup.unity.meta +++ b/Assets/Scenes/Startup.unity.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: b8799d538c243b245a875e084cdcd466 +guid: 1092174c2196ea14b9b0c877f334fe86 DefaultImporter: externalObjects: {} userData: diff --git a/Assets/Scenes/Tests/BuildModeTest.unity b/Assets/Scenes/Tests/BuildModeTest.unity new file mode 100644 index 00000000..6d522dbc --- /dev/null +++ b/Assets/Scenes/Tests/BuildModeTest.unity @@ -0,0 +1,2022 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0.44657874, g: 0.49641275, b: 0.5748172, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 12 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 512 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 256 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 1 + m_PVRDenoiserTypeDirect: 1 + m_PVRDenoiserTypeIndirect: 1 + m_PVRDenoiserTypeAO: 1 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 1 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_LightingSettings: {fileID: 0} +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &89992084 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 89992085} + - component: {fileID: 89992086} + - component: {fileID: 89992087} + m_Layer: 5 + m_Name: Handle + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &89992085 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 89992084} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 420274207} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 20, y: 20} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &89992086 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 89992084} + m_CullTransparentMesh: 1 +--- !u!114 &89992087 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 89992084} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &420274206 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 420274207} + m_Layer: 5 + m_Name: Sliding Area + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &420274207 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 420274206} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 89992085} + m_Father: {fileID: 2062259699} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: -20, y: -20} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &489915452 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 489915453} + - component: {fileID: 489915454} + m_Layer: 0 + m_Name: BuildModeTestController + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &489915453 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 489915452} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 35.671333, y: 1.8509755, z: 31.046001} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1538301813} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &489915454 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 489915452} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 94cb5833fa52cfc4392f5daf80bc17b3, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &548360276 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 548360277} + - component: {fileID: 548360279} + - component: {fileID: 548360278} + m_Layer: 0 + m_Name: curs + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &548360277 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 548360276} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 1.51, z: 0} + m_LocalScale: {x: 0.15, y: 1.5, z: 0.15} + m_Children: [] + m_Father: {fileID: 1458263242} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!23 &548360278 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 548360276} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!33 &548360279 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 548360276} + m_Mesh: {fileID: 10206, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &648965860 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 648965865} + - component: {fileID: 648965864} + - component: {fileID: 648965863} + - component: {fileID: 648965862} + - component: {fileID: 648965861} + m_Layer: 5 + m_Name: Cheat Console Canvas + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &648965861 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 648965860} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: c7d73af69c9e8614080ca76faff3ae13, type: 3} + m_Name: + m_EditorClassIdentifier: + ConsoleParent: {fileID: 1951021496} + CheatInputField: {fileID: 2114196948} + ConsoleOutput: {fileID: 1078632927} + ConsoleScroll: {fileID: 1085664058} +--- !u!114 &648965862 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 648965860} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreReversedGraphics: 1 + m_BlockingObjects: 0 + m_BlockingMask: + serializedVersion: 2 + m_Bits: 4294967295 +--- !u!114 &648965863 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 648965860} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UiScaleMode: 0 + m_ReferencePixelsPerUnit: 100 + m_ScaleFactor: 1 + m_ReferenceResolution: {x: 800, y: 600} + m_ScreenMatchMode: 0 + m_MatchWidthOrHeight: 0 + m_PhysicalUnit: 3 + m_FallbackScreenDPI: 96 + m_DefaultSpriteDPI: 96 + m_DynamicPixelsPerUnit: 1 + m_PresetInfoIsWorld: 0 +--- !u!223 &648965864 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 648965860} + m_Enabled: 1 + serializedVersion: 3 + m_RenderMode: 0 + m_Camera: {fileID: 0} + m_PlaneDistance: 100 + m_PixelPerfect: 0 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_AdditionalShaderChannelsFlag: 0 + m_SortingLayerID: 0 + m_SortingOrder: 100 + m_TargetDisplay: 0 +--- !u!224 &648965865 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 648965860} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0, y: 0, z: 0} + m_Children: + - {fileID: 1951021497} + m_Father: {fileID: 0} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0, y: 0} +--- !u!1 &783440545 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 783440546} + - component: {fileID: 783440547} + m_Layer: 5 + m_Name: Viewport + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &783440546 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 783440545} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1078632924} + m_Father: {fileID: 1085664059} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: -17, y: 0} + m_Pivot: {x: 0, y: 1} +--- !u!222 &783440547 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 783440545} + m_CullTransparentMesh: 1 +--- !u!1 &1078632923 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1078632924} + - component: {fileID: 1078632926} + - component: {fileID: 1078632927} + - component: {fileID: 1078632925} + m_Layer: 5 + m_Name: Console Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1078632924 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1078632923} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 783440546} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0, y: 1} +--- !u!114 &1078632925 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1078632923} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3245ec927659c4140ac4f8d17403cc18, type: 3} + m_Name: + m_EditorClassIdentifier: + m_HorizontalFit: 0 + m_VerticalFit: 2 +--- !u!222 &1078632926 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1078632923} + m_CullTransparentMesh: 1 +--- !u!114 &1078632927 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1078632923} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 14 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 10 + m_MaxSize: 40 + m_Alignment: 0 + m_AlignByGeometry: 0 + m_RichText: 0 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: +--- !u!1 &1085664057 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1085664059} + - component: {fileID: 1085664060} + - component: {fileID: 1085664058} + m_Layer: 5 + m_Name: Scroll View + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1085664058 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1085664057} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1aa08ab6e0800fa44ae55d278d1423e3, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Content: {fileID: 1078632924} + m_Horizontal: 0 + m_Vertical: 1 + m_MovementType: 2 + m_Elasticity: 0.1 + m_Inertia: 0 + m_DecelerationRate: 0.135 + m_ScrollSensitivity: 40 + m_Viewport: {fileID: 783440546} + m_HorizontalScrollbar: {fileID: 0} + m_VerticalScrollbar: {fileID: 2062259698} + m_HorizontalScrollbarVisibility: 2 + m_VerticalScrollbarVisibility: 1 + m_HorizontalScrollbarSpacing: -3 + m_VerticalScrollbarSpacing: -3 + m_OnValueChanged: + m_PersistentCalls: + m_Calls: [] +--- !u!224 &1085664059 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1085664057} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 783440546} + m_Father: {fileID: 1326854590} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 1.6949463, y: -105.1} + m_SizeDelta: {x: -3.3900743, y: 200} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &1085664060 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1085664057} + m_CullTransparentMesh: 1 +--- !u!1 &1134778609 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1134778610} + - component: {fileID: 1134778611} + m_Layer: 0 + m_Name: LotViewUIController + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1134778610 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1134778609} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1538301813} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1134778611 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1134778609} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9727801f799a10a41875182ace337639, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &1139364661 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1139364662} + - component: {fileID: 1139364665} + - component: {fileID: 1139364664} + m_Layer: 0 + m_Name: Plane + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1139364662 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1139364661} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 3.232, z: 0} + m_LocalScale: {x: 0.75, y: 0.75, z: 0} + m_Children: [] + m_Father: {fileID: 1458263242} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!23 &1139364664 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1139364661} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 5d46dd5277a083f49992dd646af64e34, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!33 &1139364665 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1139364661} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &1157865906 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1157865908} + - component: {fileID: 1157865907} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &1157865907 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1157865906} + m_Enabled: 1 + serializedVersion: 10 + m_Type: 1 + m_Shape: 0 + m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_UseViewFrustumForShadowCasterCull: 1 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &1157865908 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1157865906} + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 3, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!1 &1196709330 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1196709331} + - component: {fileID: 1196709333} + - component: {fileID: 1196709332} + m_Layer: 5 + m_Name: Placeholder + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1196709331 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1196709330} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 2114196945} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -0.5} + m_SizeDelta: {x: -20, y: -13} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1196709332 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1196709330} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 0.5} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 14 + m_FontStyle: 2 + m_BestFit: 0 + m_MinSize: 10 + m_MaxSize: 40 + m_Alignment: 0 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: +--- !u!222 &1196709333 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1196709330} + m_CullTransparentMesh: 1 +--- !u!1 &1267610420 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1267610421} + - component: {fileID: 1267610423} + - component: {fileID: 1267610422} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1267610421 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1267610420} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 2114196945} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -0.5} + m_SizeDelta: {x: -20, y: -13} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1267610422 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1267610420} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 14 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 10 + m_MaxSize: 40 + m_Alignment: 0 + m_AlignByGeometry: 0 + m_RichText: 0 + m_HorizontalOverflow: 1 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: +--- !u!222 &1267610423 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1267610420} + m_CullTransparentMesh: 1 +--- !u!1 &1326854589 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1326854590} + - component: {fileID: 1326854593} + - component: {fileID: 1326854592} + - component: {fileID: 1326854591} + m_Layer: 5 + m_Name: ConsolePanel + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1326854590 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1326854589} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1085664059} + - {fileID: 2062259699} + m_Father: {fileID: 1951021497} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -99.20001} + m_SizeDelta: {x: 0, y: 198.4} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1326854591 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1326854589} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 31a19414c41e5ae4aae2af33fee712f6, type: 3} + m_Name: + m_EditorClassIdentifier: + m_ShowMaskGraphic: 1 +--- !u!114 &1326854592 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1326854589} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1326854593 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1326854589} + m_CullTransparentMesh: 1 +--- !u!1 &1428817267 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1428817268} + - component: {fileID: 1428817270} + - component: {fileID: 1428817269} + m_Layer: 0 + m_Name: curs + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1428817268 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1428817267} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 1.5, z: 0} + m_LocalScale: {x: 0.1, y: 3, z: 0.1} + m_Children: [] + m_Father: {fileID: 1637446162} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!23 &1428817269 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1428817267} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 9e00eb9bc0cd7be478e657c251ce0680, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!33 &1428817270 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1428817267} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &1458263241 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1458263242} + m_Layer: 0 + m_Name: Wand + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1458263242 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1458263241} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 548360277} + - {fileID: 1139364662} + m_Father: {fileID: 0} + m_RootOrder: 6 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1538301812 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1538301813} + m_Layer: 0 + m_Name: Scene + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1538301813 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1538301812} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 2076958800} + - {fileID: 1134778610} + - {fileID: 489915453} + m_Father: {fileID: 0} + m_RootOrder: 5 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1592748653 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1592748656} + - component: {fileID: 1592748655} + - component: {fileID: 1592748654} + m_Layer: 0 + m_Name: EventSystem + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1592748654 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1592748653} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3} + m_Name: + m_EditorClassIdentifier: + m_HorizontalAxis: Horizontal + m_VerticalAxis: Vertical + m_SubmitButton: Submit + m_CancelButton: Cancel + m_InputActionsPerSecond: 10 + m_RepeatDelay: 0.5 + m_ForceModuleActive: 0 +--- !u!114 &1592748655 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1592748653} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3} + m_Name: + m_EditorClassIdentifier: + m_FirstSelected: {fileID: 0} + m_sendNavigationEvents: 1 + m_DragThreshold: 10 +--- !u!4 &1592748656 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1592748653} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1637446161 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1637446162} + m_Layer: 0 + m_Name: debugWandCompanion + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1637446162 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1637446161} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1428817268} + m_Father: {fileID: 0} + m_RootOrder: 7 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1883555802 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1883555808} + - component: {fileID: 1883555804} + - component: {fileID: 1883555803} + - component: {fileID: 1883555806} + - component: {fileID: 1883555807} + - component: {fileID: 1883555805} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!81 &1883555803 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1883555802} + m_Enabled: 1 +--- !u!20 &1883555804 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1883555802} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!114 &1883555805 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1883555802} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreReversedGraphics: 1 + m_BlockingObjects: 0 + m_BlockingMask: + serializedVersion: 2 + m_Bits: 4294967295 +--- !u!114 &1883555806 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1883555802} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 8021982501d05f645a42b19f4a41ab8a, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!223 &1883555807 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1883555802} + m_Enabled: 1 + serializedVersion: 3 + m_RenderMode: 2 + m_Camera: {fileID: 0} + m_PlaneDistance: 100 + m_PixelPerfect: 0 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_AdditionalShaderChannelsFlag: 0 + m_SortingLayerID: 0 + m_SortingOrder: 0 + m_TargetDisplay: 0 +--- !u!224 &1883555808 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1883555802} + m_LocalRotation: {x: 0.35355338, y: 0.35355338, z: -0.1464466, w: 0.8535535} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 45, y: 45, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 8} + m_SizeDelta: {x: 100, y: 100} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &1951021496 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1951021497} + m_Layer: 5 + m_Name: Cheat Console + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1951021497 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1951021496} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 2114196945} + - {fileID: 1326854590} + m_Father: {fileID: 648965865} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &2000707108 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2000707112} + - component: {fileID: 2000707111} + - component: {fileID: 2000707110} + - component: {fileID: 2000707109} + - component: {fileID: 2000707113} + m_Layer: 5 + m_Name: Canvas + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &2000707109 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2000707108} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreReversedGraphics: 1 + m_BlockingObjects: 0 + m_BlockingMask: + serializedVersion: 2 + m_Bits: 4294967295 +--- !u!114 &2000707110 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2000707108} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UiScaleMode: 0 + m_ReferencePixelsPerUnit: 100 + m_ScaleFactor: 1 + m_ReferenceResolution: {x: 800, y: 600} + m_ScreenMatchMode: 0 + m_MatchWidthOrHeight: 0 + m_PhysicalUnit: 3 + m_FallbackScreenDPI: 96 + m_DefaultSpriteDPI: 96 + m_DynamicPixelsPerUnit: 1 + m_PresetInfoIsWorld: 0 +--- !u!223 &2000707111 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2000707108} + m_Enabled: 1 + serializedVersion: 3 + m_RenderMode: 0 + m_Camera: {fileID: 0} + m_PlaneDistance: 100 + m_PixelPerfect: 1 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_AdditionalShaderChannelsFlag: 0 + m_SortingLayerID: 0 + m_SortingOrder: 0 + m_TargetDisplay: 0 +--- !u!224 &2000707112 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2000707108} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0, y: 0, z: 0} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0, y: 0} +--- !u!114 &2000707113 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2000707108} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: db3b6e6445c9df84bb2e95b9365382be, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &2062259697 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2062259699} + - component: {fileID: 2062259701} + - component: {fileID: 2062259700} + - component: {fileID: 2062259698} + m_Layer: 5 + m_Name: Scrollbar Vertical + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &2062259698 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2062259697} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2a4db7a114972834c8e4117be1d82ba3, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 89992087} + m_HandleRect: {fileID: 89992085} + m_Direction: 2 + m_Value: 0 + m_Size: 1 + m_NumberOfSteps: 0 + m_OnValueChanged: + m_PersistentCalls: + m_Calls: [] +--- !u!224 &2062259699 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2062259697} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 420274207} + m_Father: {fileID: 1326854590} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0.000015258789} + m_SizeDelta: {x: 20, y: 0} + m_Pivot: {x: 1, y: 1} +--- !u!114 &2062259700 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2062259697} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &2062259701 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2062259697} + m_CullTransparentMesh: 1 +--- !u!1001 &2076958799 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 1538301813} + m_Modifications: + - target: {fileID: 2467515431058217605, guid: 188047b711783b74aa73c17ff9d66147, type: 3} + propertyPath: m_Name + value: Scene Startup + objectReference: {fileID: 0} + - target: {fileID: 2467515431058217606, guid: 188047b711783b74aa73c17ff9d66147, type: 3} + propertyPath: m_RootOrder + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2467515431058217606, guid: 188047b711783b74aa73c17ff9d66147, type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2467515431058217606, guid: 188047b711783b74aa73c17ff9d66147, type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2467515431058217606, guid: 188047b711783b74aa73c17ff9d66147, type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2467515431058217606, guid: 188047b711783b74aa73c17ff9d66147, type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 2467515431058217606, guid: 188047b711783b74aa73c17ff9d66147, type: 3} + propertyPath: m_LocalRotation.x + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 2467515431058217606, guid: 188047b711783b74aa73c17ff9d66147, type: 3} + propertyPath: m_LocalRotation.y + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 2467515431058217606, guid: 188047b711783b74aa73c17ff9d66147, type: 3} + propertyPath: m_LocalRotation.z + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 2467515431058217606, guid: 188047b711783b74aa73c17ff9d66147, type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2467515431058217606, guid: 188047b711783b74aa73c17ff9d66147, type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2467515431058217606, guid: 188047b711783b74aa73c17ff9d66147, type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 188047b711783b74aa73c17ff9d66147, type: 3} +--- !u!4 &2076958800 stripped +Transform: + m_CorrespondingSourceObject: {fileID: 2467515431058217606, guid: 188047b711783b74aa73c17ff9d66147, type: 3} + m_PrefabInstance: {fileID: 2076958799} + m_PrefabAsset: {fileID: 0} +--- !u!1 &2114196944 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2114196945} + - component: {fileID: 2114196947} + - component: {fileID: 2114196946} + - component: {fileID: 2114196948} + m_Layer: 5 + m_Name: InputField + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2114196945 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2114196944} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1196709331} + - {fileID: 1267610421} + m_Father: {fileID: 1951021497} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -213.4} + m_SizeDelta: {x: 0, y: 30} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &2114196946 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2114196944} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10911, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &2114196947 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2114196944} + m_CullTransparentMesh: 1 +--- !u!114 &2114196948 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2114196944} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d199490a83bb2b844b9695cbf13b01ef, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 2114196946} + m_TextComponent: {fileID: 1267610422} + m_Placeholder: {fileID: 1196709332} + m_ContentType: 0 + m_InputType: 0 + m_AsteriskChar: 42 + m_KeyboardType: 0 + m_LineType: 0 + m_HideMobileInput: 0 + m_CharacterValidation: 0 + m_CharacterLimit: 0 + m_OnEndEdit: + m_PersistentCalls: + m_Calls: [] + m_OnValueChanged: + m_PersistentCalls: + m_Calls: [] + m_CaretColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_CustomCaretColor: 0 + m_SelectionColor: {r: 0.65882355, g: 0.80784315, b: 1, a: 0.7529412} + m_Text: + m_CaretBlinkRate: 0.85 + m_CaretWidth: 1 + m_ReadOnly: 0 + m_ShouldActivateOnSelect: 1 diff --git a/Assets/Scenes/Tests/BuildModeTest.unity.meta b/Assets/Scenes/Tests/BuildModeTest.unity.meta new file mode 100644 index 00000000..83aed113 --- /dev/null +++ b/Assets/Scenes/Tests/BuildModeTest.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 74352a833a6dc254ab203706be9743b9 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scenes/Tests/LotObjectSimulationTest.unity b/Assets/Scenes/Tests/LotObjectSimulationTest.unity new file mode 100644 index 00000000..d1177d75 --- /dev/null +++ b/Assets/Scenes/Tests/LotObjectSimulationTest.unity @@ -0,0 +1,347 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0.44657874, g: 0.49641275, b: 0.5748172, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 12 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 512 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 256 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 1 + m_PVRDenoiserTypeDirect: 1 + m_PVRDenoiserTypeIndirect: 1 + m_PVRDenoiserTypeAO: 1 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 1 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_LightingSettings: {fileID: 0} +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &457597077 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 457597079} + - component: {fileID: 457597078} + m_Layer: 0 + m_Name: Controller + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &457597078 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 457597077} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 54fe40fa056264c4ab3d016b539c0210, type: 3} + m_Name: + m_EditorClassIdentifier: + NeighborhoodPrefix: N002 + LotID: 22 + ItemIndex: 22 +--- !u!4 &457597079 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 457597077} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -12.6531105, y: -14.127701, z: 16.141178} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1068167770 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1068167772} + - component: {fileID: 1068167771} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &1068167771 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1068167770} + m_Enabled: 1 + serializedVersion: 10 + m_Type: 1 + m_Shape: 0 + m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_UseViewFrustumForShadowCasterCull: 1 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &1068167772 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1068167770} + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 3, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!1 &1629135009 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1629135012} + - component: {fileID: 1629135011} + - component: {fileID: 1629135010} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!81 &1629135010 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1629135009} + m_Enabled: 1 +--- !u!20 &1629135011 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1629135009} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &1629135012 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1629135009} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} diff --git a/Assets/Scenes/Tests/LotObjectSimulationTest.unity.meta b/Assets/Scenes/Tests/LotObjectSimulationTest.unity.meta new file mode 100644 index 00000000..1b263837 --- /dev/null +++ b/Assets/Scenes/Tests/LotObjectSimulationTest.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 81f031eb4c890834a9669b32fc4457d5 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/DBPFSharp/QfsCompression.cs b/Assets/Scripts/DBPFSharp/QfsCompression.cs index ac2a9005..55c808aa 100644 --- a/Assets/Scripts/DBPFSharp/QfsCompression.cs +++ b/Assets/Scripts/DBPFSharp/QfsCompression.cs @@ -75,7 +75,7 @@ internal static class QfsCompression /// If set to true prefix the size of the compressed data, as is used by SC4; otherwise false. /// A byte array containing the compressed data or null if the data cannot be compressed. /// is null. - public static byte[]? Compress(byte[] input, bool prefixLength) + public static byte[] Compress(byte[] input, bool prefixLength) { if (input == null) { @@ -415,7 +415,7 @@ int Log2(uint n) /// /// This method has been adapted from deflate.c in zlib version 1.2.3. /// - public byte[]? Compress() + public byte[] Compress() { this.hash = input[0]; this.hash = ((this.hash << hashShift) ^ input[1]) & hashMask; diff --git a/Assets/Scripts/OpenTS2/Audio/AudioManager.cs b/Assets/Scripts/OpenTS2/Audio/AudioManager.cs index 6ac84b45..fd7f347e 100644 --- a/Assets/Scripts/OpenTS2/Audio/AudioManager.cs +++ b/Assets/Scripts/OpenTS2/Audio/AudioManager.cs @@ -1,24 +1,135 @@ using OpenTS2.Common; +using OpenTS2.Common.Utils; using OpenTS2.Content; using OpenTS2.Content.DBPF; +using OpenTS2.Engine; +using OpenTS2.Files; +using OpenTS2.Files.Formats.DBPF; using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; +using UnityEngine; namespace OpenTS2.Audio { - public static class AudioManager + public class AudioManager { - readonly static ResourceKey s_splashKey = new ResourceKey(0xFF8DFFC2, 0xE4085DD2, 0xFF8DFFC2, 0x2026960B); - public static AudioAsset SplashAudio + public static AudioManager Instance { get; private set; } + [GameProperty(true)] + public static uint FXVolume = 100; + [GameProperty(true)] + public static uint VOXVolume = 100; + [GameProperty(true)] + public static uint AmbienceVolume = 100; + [GameProperty(true)] + public static uint MusicVolume = 40; + [GameProperty(true)] + public static bool MuteAudioOnFocusLoss = true; + public static Action OnInitialized; + public Dictionary CustomSongNames; + public List AudioAssets { get; private set; } + private Dictionary, ResourceKey> _audioAssetByInstanceID; + private ContentManager _contentManager; + + public AudioManager() + { + Instance = this; + Core.OnFinishedLoading += OnFinishedLoading; + } + + private void OnFinishedLoading() + { + _contentManager = ContentManager.Instance; + LoadCustomMusic(); + _audioAssetByInstanceID = new Dictionary, ResourceKey>(); + AudioAssets = _contentManager.ResourceMap.Keys.Where(key => key.TypeID == TypeIDs.AUDIO || key.TypeID == TypeIDs.HITLIST).ToList(); + foreach (var audioAsset in AudioAssets) + { + _audioAssetByInstanceID[new Tuple(audioAsset.InstanceID, 0)] = audioAsset; + _audioAssetByInstanceID[new Tuple(audioAsset.InstanceID, audioAsset.InstanceHigh)] = audioAsset; + } + OnInitialized?.Invoke(); + } + + private void LoadCustomMusic() { - get + CustomSongNames = new Dictionary(); + var musicDir = Path.Combine(Filesystem.UserDataDirectory, "Music"); + var stationDirs = Directory.GetDirectories(musicDir); + foreach(var stationDir in stationDirs) { - var contentProvider = ContentProvider.Get(); - return contentProvider.GetAsset(s_splashKey); + var stationName = Path.GetFileName(stationDir); + var audioFiles = Directory.GetFiles(stationDir, "*.*").Where(file => file.ToLowerInvariant().EndsWith(".mp3") || file.ToLowerInvariant().EndsWith(".wav")); + foreach(var audioFile in audioFiles) + { + var songName = Path.GetFileNameWithoutExtension(audioFile); + var key = new ResourceKey(songName, FileUtils.LowHash(stationName), TypeIDs.AUDIO); + _contentManager.MapFileToResource(audioFile, key); + CustomSongNames[key] = songName; + } } } + + public float GetVolumeForMixer(Mixers mixer) + { + if (MuteAudioOnFocusLoss && !Application.isFocused) + return 0f; + uint val = 100; + switch (mixer) + { + case Mixers.Voices: + val = VOXVolume; + break; + + case Mixers.SoundEffects: + val = FXVolume; + break; + + case Mixers.Music: + val = MusicVolume; + break; + + case Mixers.Ambient: + val = AmbienceVolume; + break; + } + return val / 100f; + } + + public ResourceKey GetAudioResourceKeyByInstanceID(uint instanceID, uint instanceIDHigh = 0) + { + if (_audioAssetByInstanceID.TryGetValue(new Tuple(instanceID, instanceIDHigh), out var result)) + { + return result; + } + return default; + } + + public void PlayUISound(ResourceKey audioKey) + { + var asset = _contentManager.GetAsset(audioKey); + if (asset != null) + { + var audioSource = CreateOneShotAudioSource(); + audioSource.Audio = asset; + audioSource.Mixer = Mixers.SoundEffects; + audioSource.Play(); + } + } + + private TSAudioSource CreateOneShotAudioSource() + { + var go = new GameObject("One Shot Audio Source"); + var audioSource = go.AddComponent(); + audioSource.Loop = false; + audioSource.PlaybackFinished += () => + { + UnityEngine.Object.Destroy(go); + }; + return audioSource; + } } } diff --git a/Assets/Scripts/OpenTS2/Audio/AudioManager.cs.meta b/Assets/Scripts/OpenTS2/Audio/AudioManager.cs.meta index 6d14cd4d..1e7a93ec 100644 --- a/Assets/Scripts/OpenTS2/Audio/AudioManager.cs.meta +++ b/Assets/Scripts/OpenTS2/Audio/AudioManager.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 8a3a60fb385e4f14bb7fe73fc81a5219 +guid: 3f49f2baa02d1fe40bab143ec241b9ce MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/Scripts/OpenTS2/Audio/Mixers.cs b/Assets/Scripts/OpenTS2/Audio/Mixers.cs new file mode 100644 index 00000000..9977efdc --- /dev/null +++ b/Assets/Scripts/OpenTS2/Audio/Mixers.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OpenTS2.Audio +{ + public enum Mixers + { + Voices, + SoundEffects, + Music, + Ambient + } +} diff --git a/Assets/Scripts/OpenTS2/Audio/Mixers.cs.meta b/Assets/Scripts/OpenTS2/Audio/Mixers.cs.meta new file mode 100644 index 00000000..14eecb06 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Audio/Mixers.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 62159423f4ffb7d40bc6aef1bf588f14 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Audio/MusicCategory.cs b/Assets/Scripts/OpenTS2/Audio/MusicCategory.cs new file mode 100644 index 00000000..e12ea186 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Audio/MusicCategory.cs @@ -0,0 +1,63 @@ +using OpenTS2.Common; +using OpenTS2.Common.Utils; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OpenTS2.Audio +{ + public class MusicCategory + { + public List CurrentPlaylist; + public string LocalizedName; + public string Name { get; private set; } + public uint Hash { get; private set; } + private string[] _rawPlaylist; + + public MusicCategory(string name, string[] playlist) + { + Name = name; + Hash = FileUtils.LowHash(name); + _rawPlaylist = playlist; + } + + public MusicCategory(string name, uint hash) + { + Name = name; + Hash = hash; + _rawPlaylist = new string[] { name }; + } + + public Song PopNextSong() + { + var song = CurrentPlaylist[0]; + if (CurrentPlaylist.Count <= 1) + { + InitializePlaylist(); + if (CurrentPlaylist.Count <= 1) + return song; + } + CurrentPlaylist.Remove(song); + return song; + } + + public void InitializePlaylist() + { + CurrentPlaylist = new List(); + var musicManager = MusicManager.Instance; + foreach(var playlistName in _rawPlaylist) + { + var playList = new List(musicManager.GetPlaylist(playlistName)); + playList.Shuffle(); + CurrentPlaylist.AddRange(playList); + } + var playlistsText = ""; + foreach (var playlist in _rawPlaylist) + { + playlistsText += $"{playlist} "; + } + } + } +} diff --git a/Assets/Scripts/OpenTS2/Audio/MusicCategory.cs.meta b/Assets/Scripts/OpenTS2/Audio/MusicCategory.cs.meta new file mode 100644 index 00000000..bc9feae6 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Audio/MusicCategory.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 790aab67d6a5f8340a2231333b68276c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Audio/MusicController.cs b/Assets/Scripts/OpenTS2/Audio/MusicController.cs index 82573837..d6743f9b 100644 --- a/Assets/Scripts/OpenTS2/Audio/MusicController.cs +++ b/Assets/Scripts/OpenTS2/Audio/MusicController.cs @@ -1,4 +1,5 @@ using OpenTS2.Content.DBPF; +using OpenTS2.Engine; using System; using System.Collections; using System.Collections.Generic; @@ -6,58 +7,160 @@ using System.Text; using System.Threading.Tasks; using UnityEngine; +using OpenTS2.Content; +using System.IO; +using Unity.Collections; +using System.Security.Cryptography; namespace OpenTS2.Audio { - [RequireComponent(typeof(AudioSource))] + [RequireComponent(typeof(TSAudioSource))] public class MusicController : MonoBehaviour { - public static MusicController Singleton => s_singleton; - static MusicController s_singleton = null; - private AudioSource _audioSource; - private AudioAsset _currentAudioAsset; + public static MusicController Instance { get; private set; } + private const float FadeSpeed = 0.5f; + private TSAudioSource _tsAudioSource; + private MusicCategory _currentMusicCategory = null; + private enum States + { + Stopped, + Playing, + Paused, + FadingOut, + FadingIn + } + private States _state = States.Stopped; + private float _currentVolumeMultiplier = 1f; - private void Awake() + public void Stop() { - if (s_singleton != null) + if (_state == States.Stopped) return; + _currentMusicCategory = null; + if (_state == States.Paused) { - Destroy(gameObject); + _tsAudioSource.Stop(); + _state = States.Stopped; return; } - s_singleton = this; - DontDestroyOnLoad(gameObject); - _audioSource = GetComponent(); + _state = States.FadingOut; } - public static void PlayMusic(AudioAsset music) + public void Pause() { - Singleton._currentAudioAsset = music; - Singleton._audioSource.clip = music.Clip; - Singleton._audioSource.volume = 1f; - Singleton._audioSource.Play(); + _state = States.Paused; + _tsAudioSource.Pause(); } - public static void FadeOutMusic() + public void Resume() { - Singleton.StartCoroutine(Singleton.FadeOut()); + _state = States.Playing; + _tsAudioSource.Resume(); } - IEnumerator FadeOut() + private void UpdateVolumeMultiplier() { - var volume = _audioSource.volume; - while (volume > 0f) + if (_state == States.FadingOut) + { + _currentVolumeMultiplier -= FadeSpeed * Time.unscaledDeltaTime; + if (_currentVolumeMultiplier < 0f) + { + _currentVolumeMultiplier = 0f; + if (_currentMusicCategory == null) + { + _tsAudioSource.Stop(); + _state = States.Stopped; + } + else + { + PlayNextSong(); + _state = States.FadingIn; + } + } + } + else if (_state == States.FadingIn) { - volume -= 0.5f * Time.deltaTime; - _audioSource.volume = volume; - yield return null; + _currentVolumeMultiplier += FadeSpeed * Time.unscaledDeltaTime; + if (_currentVolumeMultiplier >= 1f) + { + _currentVolumeMultiplier = 1f; + _state = States.Playing; + } } - StopMusic(); + else + _currentVolumeMultiplier = 1f; + if (_state == States.Stopped) + _currentVolumeMultiplier = 0f; + } + + private void UpdateVolume() + { + _tsAudioSource.Volume = _currentVolumeMultiplier; + } + + public void StartMusicCategory(string musicCategory) + { + _tsAudioSource.PlaybackFinished -= OnSongEnd; + _tsAudioSource.PlaybackFinished += OnSongEnd; + _tsAudioSource.Loop = false; + _currentMusicCategory = MusicManager.Instance.GetMusicCategory(musicCategory); + _state = States.FadingOut; + if (_state == States.Stopped) + { + _state = States.FadingIn; + PlayNextSong(); + } + } + + private void Awake() + { + Instance = this; + _tsAudioSource = GetComponent(); + UpdateVolume(); + Core.OnNeighborhoodEntered += OnNeighborhoodEntered; + Core.OnBeginLoading += OnBeginLoadingScreen; + Core.OnLotLoaded += OnLotLoaded; } - void StopMusic() + private void Update() { - _audioSource.Stop(); - _currentAudioAsset = null; + UpdateVolumeMultiplier(); + UpdateVolume(); + } + + private void OnBeginLoadingScreen() + { + _tsAudioSource.Audio = MusicManager.SplashAudio; + _tsAudioSource.Loop = true; + _tsAudioSource.Play(); + _state = States.Playing; + } + + private void OnNeighborhoodEntered() + { + StartMusicCategory("NHood"); + } + + private void OnLotLoaded() + { + if (CASManager.Instance.InCAS) + StartMusicCategory("CAS"); + else + Stop(); + } + + private void PlayNextSong() + { + StopAllCoroutines(); + var contentManager = ContentManager.Instance; + var currentSong = _currentMusicCategory.PopNextSong(); + _tsAudioSource.PlayAsync(currentSong.Key); + } + + private void OnSongEnd() + { + if (_state == States.FadingOut) + return; + PlayNextSong(); } } } diff --git a/Assets/Scripts/OpenTS2/Audio/MusicManager.cs b/Assets/Scripts/OpenTS2/Audio/MusicManager.cs new file mode 100644 index 00000000..0d840ce4 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Audio/MusicManager.cs @@ -0,0 +1,204 @@ +using OpenTS2.Common; +using OpenTS2.Common.Utils; +using OpenTS2.Content; +using OpenTS2.Content.DBPF; +using OpenTS2.Engine; +using OpenTS2.Files.Formats.DBPF; +using OpenTS2.Files.Formats.XML; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEditor; +using UnityEngine; +using OpenTS2.Files; +using OpenTS2.Files.Formats.Ini; + +namespace OpenTS2.Audio +{ + public class MusicManager + { + public static AudioAsset SplashAudio + { + get + { + var contentManager = ContentManager.Instance; + return contentManager.GetAsset(SplashKey); + } + } + + public static MusicManager Instance { get; private set; } + + readonly static ResourceKey MusicCategoriesXMLKey = new ResourceKey(0xFFD3706D, 0x38888A91, 0x4C1940C5, 0xEBFEE33F); + readonly static ResourceKey SplashKey = new ResourceKey(0xFF8DFFC2, 0xE4085DD2, 0xFF8DFFC2, 0x2026960B); + + public Dictionary MusicCategoryByHash = new Dictionary(); + public Dictionary> PlaylistByHash = new Dictionary>(); + + private ContentManager _contentManager; + + public MusicCategory GetMusicCategory (string name) + { + var hash = FileUtils.LowHash(name); + return GetMusicCategory(hash); + } + + public MusicCategory GetMusicCategory(uint hash) + { + if (MusicCategoryByHash.TryGetValue(hash, out var category)) + return category; + return null; + } + + public List GetPlaylist(string name) + { + var hash = FileUtils.LowHash(name); + return GetPlaylist(hash); + } + + public List GetPlaylist(uint hash) + { + if (PlaylistByHash.TryGetValue(hash, out var playlist)) + return playlist; + return null; + } + + private List GetMusicTitles() + { + var musicTitlesGroupID = FileUtils.GroupHash("MusicTitles"); + var musicStringSets = _contentManager.ResourceMap.Keys.Where(x => x.GroupID == musicTitlesGroupID && x.TypeID == TypeIDs.STR).ToList(); + return musicStringSets; + } + + private void InitializeMusicCategoryPlaylists() + { + foreach(var musicCategory in MusicCategoryByHash) + { + musicCategory.Value.InitializePlaylist(); + } + } + + private void LoadPlaylists(List musicTitles) + { + var audioResourceKeys = AudioManager.Instance.AudioAssets; + foreach(var musicCategory in MusicCategoryByHash) + { + var resourceKeys = audioResourceKeys.Where(x => x.GroupID == musicCategory.Key).ToList(); + var songList = new List(); + foreach(var key in resourceKeys) + { + var localizedName = key.ToString(); + if (AudioManager.Instance.CustomSongNames.TryGetValue(key, out var customSongName)) + { + localizedName = customSongName; + } + else + { + foreach (var musicTitle in musicTitles) + { + var stringSet = _contentManager.GetAsset(musicTitle); + var englishStrings = stringSet.StringData.Strings[Languages.USEnglish]; + + for (var i = 0; i < englishStrings.Count; i++) + { + var englishString = englishStrings[i].Value; + var hiHash = FileUtils.HighHash(englishString); + if (hiHash == key.InstanceHigh) + { + localizedName = stringSet.GetString(i); + } + } + } + } + var song = new Song(key, localizedName); + songList.Add(song); + } + PlaylistByHash[musicCategory.Key] = songList; + } + } + + private void LocalizeMusicCategories(List musicTitles) + { + foreach (var stringSetKey in musicTitles) + { + var stringSet = _contentManager.GetAsset(stringSetKey); + + var englishStrings = stringSet.StringData.Strings[Languages.USEnglish]; + + for (var i = 0; i < englishStrings.Count; i++) + { + var englishString = englishStrings[i].Value; + var loHash = FileUtils.LowHash(englishString); + if (MusicCategoryByHash.TryGetValue(loHash, out var category)) + { + category.LocalizedName = stringSet.GetString(i); + } + } + } + } + + private void LoadIniMusicCategories() + { + var products = Filesystem.GetProductDirectories(); + foreach(var product in products) + { + var sysFolder = Path.Combine(product, "TSData/Sys"); + if (!Directory.Exists(sysFolder)) continue; + var unpackedAudioIni = Directory.GetFiles(sysFolder, "TSAudioUnpacked*.ini", SearchOption.TopDirectoryOnly).FirstOrDefault(); + if (!string.IsNullOrEmpty(unpackedAudioIni)) + { + var iniFile = new IniFile(unpackedAudioIni); + var musicSection = iniFile.GetSection("MusicDirectories"); + if (musicSection != null) + { + foreach(var prop in musicSection.KeyValues) + { + var name = prop.Key; + var hash = Convert.ToUInt32(prop.Value, 16); + if (MusicCategoryByHash.ContainsKey(hash)) continue; + + var musicCategory = new MusicCategory(name, hash); + MusicCategoryByHash[musicCategory.Hash] = musicCategory; + } + } + } + } + } + + private void LoadMusicCategories() + { + var musicCategoriesEntry = _contentManager.GetEntry(MusicCategoriesXMLKey); + if (musicCategoriesEntry == null) + throw new IOException("Can't find Music Categories XML!"); + var musicCategoriesBytes = musicCategoriesEntry.GetBytes(); + var xml = new PropertySet(musicCategoriesBytes); + if (xml == null) + throw new IOException("Can't load Music Categories XML!"); + + foreach (var prop in xml.Properties) + { + var musicCategory = new MusicCategory(prop.Key, ((StringProp)prop.Value).Value.Split(',')); + MusicCategoryByHash[musicCategory.Hash] = musicCategory; + } + } + + public MusicManager() + { + Instance = this; + _contentManager = ContentManager.Instance; + AudioManager.OnInitialized += Initialize; + } + + private void Initialize() + { + var musicTitles = GetMusicTitles(); + LoadMusicCategories(); + LoadIniMusicCategories(); + LocalizeMusicCategories(musicTitles); + LoadPlaylists(musicTitles); + InitializeMusicCategoryPlaylists(); + } + } +} diff --git a/Assets/Scripts/OpenTS2/Audio/MusicManager.cs.meta b/Assets/Scripts/OpenTS2/Audio/MusicManager.cs.meta new file mode 100644 index 00000000..6d14cd4d --- /dev/null +++ b/Assets/Scripts/OpenTS2/Audio/MusicManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8a3a60fb385e4f14bb7fe73fc81a5219 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Audio/Song.cs b/Assets/Scripts/OpenTS2/Audio/Song.cs new file mode 100644 index 00000000..4bfd297d --- /dev/null +++ b/Assets/Scripts/OpenTS2/Audio/Song.cs @@ -0,0 +1,21 @@ +using OpenTS2.Common; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OpenTS2.Audio +{ + public class Song + { + public ResourceKey Key; + public string LocalizedName; + + public Song(ResourceKey key, string localizedName) + { + Key = key; + LocalizedName = localizedName; + } + } +} diff --git a/Assets/Scripts/OpenTS2/Audio/Song.cs.meta b/Assets/Scripts/OpenTS2/Audio/Song.cs.meta new file mode 100644 index 00000000..088b2c18 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Audio/Song.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 05a5bb00a71b26347abffdc72240a57a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Audio/TSAudioSource.cs b/Assets/Scripts/OpenTS2/Audio/TSAudioSource.cs new file mode 100644 index 00000000..f98bf54a --- /dev/null +++ b/Assets/Scripts/OpenTS2/Audio/TSAudioSource.cs @@ -0,0 +1,154 @@ +using OpenTS2.Audio; +using OpenTS2.Common; +using OpenTS2.Content; +using OpenTS2.Content.DBPF; +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using UnityEngine; + +/// +/// Wrapper for Unity audio source and NAudio, for playing WAV and MP3. +/// +public class TSAudioSource : MonoBehaviour +{ + public AudioAsset Audio + { + get + { + return _audio; + } + set + { + _audio = value; + CleanUp(); + } + } + public Mixers Mixer = Mixers.SoundEffects; + public bool Loop = false; + public float Volume = 1f; + public Action PlaybackFinished; + private AudioAsset _audio; + private AudioSource _audioSource; + private float _timeAudioSourcePlaying = 0f; + private bool _audioClipPlaying = false; + private bool _paused = false; + private ContentManager _contentManager; + + public void Pause() + { + if (_paused) + return; + _audioSource.Pause(); + _paused = true; + } + + public void Resume() + { + if (!_paused) + return; + _audioSource.UnPause(); + _paused = false; + } + + public void Play() + { + CleanUp(); + PlayInternal(Audio); + } + + public void PlayAsync(ResourceKey audioResourceKey) + { + CleanUp(); + Task.Run(() => + { + _audio = _contentManager.GetAsset(audioResourceKey); + }).ContinueWith(task => + { + PlayInternal(_audio); + }, TaskScheduler.FromCurrentSynchronizationContext()); + } + + private void PlayInternal(AudioAsset asset) + { + if (asset is HitListAsset) + { + asset = (asset as HitListAsset).GetRandomAudioAsset(); + PlayInternal(asset); + return; + } + PlayWAV(asset); + } + + public void Stop() + { + CleanUp(); + } + + private void Awake() + { + _contentManager = ContentManager.Instance; + _audioSource = GetComponent(); + if (_audioSource == null) + { + _audioSource = gameObject.AddComponent(); + _audioSource.playOnAwake = false; + } + } + + private void CleanUp() + { + StopAllCoroutines(); + _audioSource.Stop(); + _audioSource.clip = null; + _audioClipPlaying = false; + _timeAudioSourcePlaying = 0f; + _paused = false; + } + + private void PlayWAV(AudioAsset asset) + { + _audioClipPlaying = true; + _timeAudioSourcePlaying = 0f; + _audioSource.spatialBlend = 0f; + UpdateVolume(); + _audioSource.clip = (asset as WAVAudioAsset).Clip; + _audioSource.loop = Loop; + _audioSource.Play(); + } + + private void UpdateVolume() + { + var volume = Volume * AudioManager.Instance.GetVolumeForMixer(Mixer); + _audioSource.volume = volume; + } + + private void Update() + { + _audioSource.loop = Loop; + UpdateVolume(); + + if (_audioSource.clip != null && _audioClipPlaying && !Loop) + { + if (!_paused) + { + _timeAudioSourcePlaying += Time.unscaledDeltaTime; + if (_timeAudioSourcePlaying >= _audioSource.clip.length && !_audioSource.isPlaying) + { + _audioClipPlaying = false; + _timeAudioSourcePlaying = 0f; + PlaybackFinished?.Invoke(); + } + } + } + else + _timeAudioSourcePlaying = 0f; + } + + private void OnDestroy() + { + CleanUp(); + } +} diff --git a/Assets/Scripts/OpenTS2/Audio/TSAudioSource.cs.meta b/Assets/Scripts/OpenTS2/Audio/TSAudioSource.cs.meta new file mode 100644 index 00000000..279f0288 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Audio/TSAudioSource.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a36a87e28e05b91479c6b0d82765f248 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Cameras.meta b/Assets/Scripts/OpenTS2/Cameras.meta new file mode 100644 index 00000000..c8ef2231 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Cameras.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 47b4f5547f913ba4882d83a6ffa154e4 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Cameras/TestLotViewCamera.cs b/Assets/Scripts/OpenTS2/Cameras/TestLotViewCamera.cs new file mode 100644 index 00000000..fc1f6166 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Cameras/TestLotViewCamera.cs @@ -0,0 +1,140 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +public class TestLotViewCamera : MonoBehaviour +{ + const int HitscanLength = 2000; + + Camera _camera; + Transform _camTransform; + Vector3 mouseholdPosition; + float initialXCamRot; + + //level detection system + /// + /// A set of mesh colliders that the camera will shoot rays at to detect where the mouse cursor is in 3D world space + /// and also where the floor is to adjust its Y position to see the floor appropriately + /// See: + /// + Dictionary floorElevationMeshes; + + // Start is called before the first frame update + void Start() + { + floorElevationMeshes = new Dictionary(); + _camTransform = GetComponentInParent(); + _camera = GetComponentInParent(); + } + + // Update is called once per frame + void Update() + { + if (Input.GetMouseButtonDown(1) || Input.GetMouseButtonDown(2)) // right or middle click + { + mouseholdPosition = Input.mousePosition; + if (Input.GetMouseButtonDown(2)) + initialXCamRot = _camTransform.rotation.eulerAngles.x; + } + + var mouseChange = mouseholdPosition - Input.mousePosition; + + if (Input.GetMouseButton(1)) // Right Click camera translation + { + var change = mouseChange / 10; + _camTransform.TransformDirection(change); + change *= Time.deltaTime; + + _camTransform.position = + new Vector3(_camTransform.position.x - change.x, + _camTransform.position.y, + _camTransform.position.z - change.y); + } + else if (Input.GetMouseButton(2)) // Middle Mouse Click Camera pitch + { + float pitchChange = (mouseChange / 1).y; + var transformedXRot = Math.Max(0, Math.Min(90, initialXCamRot - pitchChange)); + var currentAngle = _camTransform.rotation.eulerAngles; + currentAngle = new Vector3(transformedXRot, currentAngle.y, currentAngle.z); + _camTransform.rotation = Quaternion.Euler(currentAngle); + } + } + + /// + /// Sets the mesh colliders used to detect the height of the floor the camera is looking at. + /// + /// + /// + public void SetCameraDetectionMeshes(int Floor, IEnumerable Colliders) + { + floorElevationMeshes.Remove(Floor); + floorElevationMeshes.Add(Floor, Colliders.Where(x => x != default).ToArray()); + } + + public static Ray GetMouseCursor3DRay(Camera SelectedCamera) + { + //transform scr pos to world + Vector3 mousePosition = Input.mousePosition; + mousePosition.z = 20; + mousePosition = Camera.main.ScreenToWorldPoint(mousePosition); + + //get directional vector + var direction = (mousePosition - SelectedCamera.transform.position); direction.Normalize(); + + //build a ray from camera to terrain + return new Ray(SelectedCamera.transform.position, direction); + } + + /// + /// Potentially expensive!! use with caution + /// + /// + /// + /// + public bool TranslateScreen2WorldPos(int MaxFloor, out Vector3 WorldPosition, out int Floor) + { + WorldPosition = new Vector3(); + Floor = -1; + + if (!floorElevationMeshes.Any()) + { + Debug.LogWarning("No terrain meshes added to the lot camera so hit detection is disabled!"); + return false; + } + + Ray camRay = GetMouseCursor3DRay(_camera); + + //Check each floor by casting the above ray at each collider. + //TODO: (NEEDS REFACTOR TO USE ELEVATION IN LOT DATA) + //also just in general this iteration is really not great should only be used on frames where theres actual movement + RaycastHit hitInfo = default; + bool hitComplete = false; + + //go top down searching for which floor we're looking at + for(int floor = MaxFloor; floor >= floorElevationMeshes.Keys.Min(); floor--) + { + if (!floorElevationMeshes.ContainsKey(floor)) continue; + foreach(var collider in floorElevationMeshes[floor]) + { + if (collider is MeshCollider mCollider) + { + var meshRef = collider.gameObject.GetComponent().sharedMesh; + mCollider.sharedMesh = meshRef; + } + if (collider.Raycast(camRay, out hitInfo, HitscanLength)) + { + hitComplete = true; + Floor = floor; + break; + } + } + if (hitComplete) break; + } + if (!hitComplete) return false; + + WorldPosition = hitInfo.point; + return true; + } +} diff --git a/Assets/Scripts/OpenTS2/Cameras/TestLotViewCamera.cs.meta b/Assets/Scripts/OpenTS2/Cameras/TestLotViewCamera.cs.meta new file mode 100644 index 00000000..2d9470ac --- /dev/null +++ b/Assets/Scripts/OpenTS2/Cameras/TestLotViewCamera.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8021982501d05f645a42b19f4a41ab8a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Client/Settings.cs b/Assets/Scripts/OpenTS2/Client/Settings.cs deleted file mode 100644 index e1fce79f..00000000 --- a/Assets/Scripts/OpenTS2/Client/Settings.cs +++ /dev/null @@ -1,33 +0,0 @@ -/* - * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. - * If a copy of the MPL was not distributed with this file, You can obtain one at - * http://mozilla.org/MPL/2.0/. - */ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OpenTS2.Client -{ - /// - /// Stores global user specific settings such as language. - /// - public class Settings - { - static Settings s_instance; - public Languages Language = Languages.USEnglish; - public bool CustomContentEnabled = true; - - public static Settings Get() - { - return s_instance; - } - public Settings() - { - s_instance = this; - } - } -} diff --git a/Assets/Scripts/OpenTS2/Common/ResourceKey.cs b/Assets/Scripts/OpenTS2/Common/ResourceKey.cs index ada132b4..1c300a47 100644 --- a/Assets/Scripts/OpenTS2/Common/ResourceKey.cs +++ b/Assets/Scripts/OpenTS2/Common/ResourceKey.cs @@ -19,37 +19,26 @@ namespace OpenTS2.Common /// public struct ResourceKey { - public static ResourceKey DIR + public bool Valid { - get { return s_dir; } + get + { + if (InstanceID == 0 && InstanceHigh == 0 && GroupID == 0 && TypeID == 0) + return false; + return true; + } } - public uint InstanceID - { - get { return _instanceID; } - } + public static ResourceKey DIR { get; private set; } = new ResourceKey(0x286B1F03, 0xE86B1EEF, 0xE86B1EEF); - public uint InstanceHigh - { - get { return _instanceHigh; } - } + public uint InstanceID { get; private set; } - public uint GroupID - { - get { return _groupID; } - } + public uint InstanceHigh { get; private set; } - public uint TypeID - { - get { return _typeID; } - } + public uint GroupID { get; private set; } - static readonly ResourceKey s_dir = new ResourceKey(0x286B1F03, 0xE86B1EEF, 0xE86B1EEF); + public uint TypeID { get; private set; } - private readonly uint _instanceID; - private readonly uint _instanceHigh; - private readonly uint _groupID; - private readonly uint _typeID; /// /// Returns new TGI with its Group ID replaced with Groups.Local, but only if our Group ID equals localGroupID @@ -87,10 +76,10 @@ public ResourceKey WithGroupID(uint groupID) /// Type ID public ResourceKey(uint instanceID, uint groupID, uint typeID) { - this._instanceID = instanceID; - this._instanceHigh = 0x00000000; - this._groupID = groupID; - this._typeID = typeID; + this.InstanceID = instanceID; + this.InstanceHigh = 0x00000000; + this.GroupID = groupID; + this.TypeID = typeID; } /// @@ -102,10 +91,10 @@ public ResourceKey(uint instanceID, uint groupID, uint typeID) /// Type ID public ResourceKey(uint instanceID, uint instanceHigh, uint groupID, uint typeID) { - this._instanceID = instanceID; - this._instanceHigh = instanceHigh; - this._groupID = groupID; - this._typeID = typeID; + this.InstanceID = instanceID; + this.InstanceHigh = instanceHigh; + this.GroupID = groupID; + this.TypeID = typeID; } /// @@ -117,10 +106,10 @@ public ResourceKey(uint instanceID, uint instanceHigh, uint groupID, uint typeID /// Type ID public ResourceKey(string filename, uint groupID, uint typeID) { - this._instanceID = FileUtils.LowHash(filename); - this._instanceHigh = FileUtils.HighHash(filename); - this._groupID = groupID; - this._typeID = typeID; + this.InstanceID = FileUtils.LowHash(filename); + this.InstanceHigh = FileUtils.HighHash(filename); + this.GroupID = groupID; + this.TypeID = typeID; } /// /// Creates a Instance ID, Instance (High), Group ID and Type ID reference. @@ -131,10 +120,10 @@ public ResourceKey(string filename, uint groupID, uint typeID) /// Type ID public ResourceKey(string filename, string groupName, uint typeID) { - this._instanceID = FileUtils.LowHash(filename); - this._instanceHigh = FileUtils.HighHash(filename); - this._groupID = FileUtils.GroupHash(groupName); - this._typeID = typeID; + this.InstanceID = FileUtils.LowHash(filename); + this.InstanceHigh = FileUtils.HighHash(filename); + this.GroupID = FileUtils.GroupHash(groupName); + this.TypeID = typeID; } /// /// Creates a Instance ID, Instance (High), Group ID and Type ID reference. @@ -146,10 +135,10 @@ public ResourceKey(string filename, string groupName, uint typeID) /// Type ID public ResourceKey(uint instanceID, uint instanceHigh, string groupName, uint typeID) { - this._instanceID = instanceID; - this._instanceHigh = instanceHigh; - this._groupID = FileUtils.GroupHash(groupName); - this._typeID = typeID; + this.InstanceID = instanceID; + this.InstanceHigh = instanceHigh; + this.GroupID = FileUtils.GroupHash(groupName); + this.TypeID = typeID; } /// /// Creates a Instance ID, Group ID and Type ID reference. @@ -160,10 +149,10 @@ public ResourceKey(uint instanceID, uint instanceHigh, string groupName, uint ty /// Type ID public ResourceKey(uint instanceID, string groupName, uint typeID) { - this._instanceID = instanceID; - this._instanceHigh = 0x00000000; - this._groupID = FileUtils.GroupHash(groupName); - this._typeID = typeID; + this.InstanceID = instanceID; + this.InstanceHigh = 0x00000000; + this.GroupID = FileUtils.GroupHash(groupName); + this.TypeID = typeID; } /// @@ -188,10 +177,10 @@ public override int GetHashCode() unchecked // Overflow is fine, just wrap { int hash = 17; - hash = hash * 23 + _instanceID.GetHashCode(); - hash = hash * 23 + _instanceHigh.GetHashCode(); - hash = hash * 23 + _typeID.GetHashCode(); - hash = hash * 23 + _groupID.GetHashCode(); + hash = hash * 23 + InstanceID.GetHashCode(); + hash = hash * 23 + InstanceHigh.GetHashCode(); + hash = hash * 23 + TypeID.GetHashCode(); + hash = hash * 23 + GroupID.GetHashCode(); return hash; } } diff --git a/Assets/Scripts/OpenTS2/Components/AssetReferenceComponent.cs b/Assets/Scripts/OpenTS2/Components/AssetReferenceComponent.cs index 2427d0eb..563fba2a 100644 --- a/Assets/Scripts/OpenTS2/Components/AssetReferenceComponent.cs +++ b/Assets/Scripts/OpenTS2/Components/AssetReferenceComponent.cs @@ -1,6 +1,12 @@ -using OpenTS2.Content; +using OpenTS2.Common; +using OpenTS2.Content; +using OpenTS2.Content.DBPF; +using OpenTS2.Content.DBPF.Scenegraph; +using OpenTS2.Files.Formats.DBPF; +using OpenTS2.Scenes.Lot; using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -16,5 +22,133 @@ public void AddReference(params AbstractAsset[] assets) { References.AddRange(assets); } + + /// + /// Indicates that this component should re-evaluate itself for changes made at runtime + /// + public virtual void Invalidate() { } + } + + // Seems like functionality is identical between certain lot components that utilize patterns. + // Moved the duplicated code to one unit so we can make improvements + + //**CURRENTLY UNUSED** + /// + /// Serves functionality for loading pattern assets from a pattern map (floors, walls, etc.) + /// + /// + public abstract class AssetPatternReferenceComponent : AssetReferenceComponent + { + /// + /// The material to use when the requested material could not be loaded using the + /// default implementation + /// + protected abstract string FallbackMaterial { get; } + /// + /// The texture to use for the thickness of the object + /// Walls and floors utilize this to show they're three-dimensional and it applied to [0] + /// + protected abstract string ThicknessTexture { get; } + + protected abstract int FloorCount { get; } + + protected PatternMeshCollection _patterns; + protected PatternDescriptor[] _loadedPatternDescriptions; + + protected abstract Dictionary Map { get; } + protected virtual Dictionary Builtins { get; } = null; + + /// + /// Base load patterns function + /// + protected virtual void LoadPatterns() + { + var contentProvider = ContentProvider.Get(); + var catalogManager = CatalogManager.Get(); + var patternMap = Map; + + ushort highestId = patternMap.Count == 0 ? (ushort)0 : patternMap.Keys.Max(); + PatternDescriptor[] patterns = new PatternDescriptor[highestId + 2]; + + bool changesMade = false; + bool previousStateExisting = _loadedPatternDescriptions != null; + + foreach (StringMapEntry entry in patternMap.Values) + { + //Persistent data -- calls from Invalidate() will call this with data already loaded, in which case + //We can save time by not reloading the same loaded data + // TODO + if (previousStateExisting && _loadedPatternDescriptions.Length == patterns.Length && + _loadedPatternDescriptions[entry.Id + 1].Name != null) // loaded + { // PatternDescriptor is a struct -- check the name see if it's null, if not, the pattern is loaded already + patterns[entry.Id + 1] = _loadedPatternDescriptions[entry.Id + 1]; + continue; + } + changesMade = true; + + string materialName = null; + if (uint.TryParse(entry.Value, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out uint guid)) + { + var catalogEntry = catalogManager.GetEntryById(guid); + + materialName = catalogEntry?.Material ?? FallbackMaterial; + } + else if (Builtins != null && !Builtins.TryGetValue(entry.Value, out materialName)) + { + materialName = entry.Value.StartsWith("wall_") ? (entry.Value + "_base") : ("wall_" + entry.Value + "_base"); + } + + if (materialName == null) + { + // Explicitly remove this pattern. + continue; + } + + // Try fetch the texture using the material name. + var material = LoadMaterial(contentProvider, materialName); + + try + { + // Note: Sometimes walls use the standard material, but we want them to use a special shader for cutaways. + patterns[entry.Id + 1] = new PatternDescriptor( + materialName, + material == null ? null : material?.GetAsUnityMaterial("Wallpaper") + ); + } + catch (Exception e) + { + Debug.LogException(e); + } + } + + if (previousStateExisting) + { + if (!changesMade) return; // no changes to wall patterns since last load + + patterns[0] = _loadedPatternDescriptions[0]; + _loadedPatternDescriptions = patterns; + _patterns.UpdatePatterns(patterns); + return; + } + + PostLoadPatterns(contentProvider, ref patterns); + + _loadedPatternDescriptions = patterns; + //_patterns = new PatternMeshCollection(gameObject, patterns, Array.Empty(), this, FloorCount); + } + + protected virtual ScenegraphMaterialDefinitionAsset LoadMaterial(ContentProvider contentProvider, string name) + { + var material = contentProvider.GetAsset(new ResourceKey($"{name}_txmt", GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_TXMT)); + + AddReference(material); + + return material; + } + + protected virtual void PostLoadPatterns(ContentProvider contentProvider, ref PatternDescriptor[] patterns) + { + + } } } diff --git a/Assets/Scripts/OpenTS2/Components/ScenegraphComponent.cs b/Assets/Scripts/OpenTS2/Components/ScenegraphComponent.cs index 9ddcafe1..483e9f3e 100644 --- a/Assets/Scripts/OpenTS2/Components/ScenegraphComponent.cs +++ b/Assets/Scripts/OpenTS2/Components/ScenegraphComponent.cs @@ -24,11 +24,6 @@ public class ScenegraphComponent : MonoBehaviour /// /// The returned game object carries a transform to convert it from sims coordinate space to unity space. /// - public static GameObject CreateRootScenegraph(ScenegraphResourceAsset resourceAsset) - { - return CreateRootScenegraph(new []{ resourceAsset }); - } - public static GameObject CreateRootScenegraph(params ScenegraphResourceAsset[] resourceAssets) { var scenegraph = CreateScenegraphComponent(resourceAssets); @@ -246,7 +241,7 @@ private static void HandleExtension(GameObject parent, DataListExtensionBlock ex var slotName = effectSlotToName.Name; var effectName = effectSlotToName.Value; // The game seriously has effects in the scenegraph that don't exist... ignore those - if (!EffectsManager.Get().Ready || !EffectsManager.Get().HasEffect(effectName)) + if (!EffectsManager.Instance.Ready || !EffectsManager.Instance.HasEffect(effectName)) { continue; } @@ -256,7 +251,7 @@ private static void HandleExtension(GameObject parent, DataListExtensionBlock ex // the scenegraph has its own MonoBehavior. try { - var swarmParticleSystem = EffectsManager.Get().CreateEffect(effectName); + var swarmParticleSystem = EffectsManager.Instance.CreateEffect(effectName); swarmParticleSystem.transform.SetParent(parent.transform, worldPositionStays: false); swarmParticleSystem.PlayEffect(); } @@ -338,7 +333,7 @@ private static void RenderResourceNode(GameObject parent, ScenegraphResourceColl Debug.Assert(resourceRef is ExternalReference); var key = rCol.FileLinks[((ExternalReference)resourceRef).FileLinksIndex]; - var resourceAsset = ContentProvider.Get().GetAsset(key); + var resourceAsset = ContentManager.Instance.GetAsset(key); if (resourceAsset == null) { Debug.LogWarning($"Unable to find cResourceNode with key {key} and name {resource.ResourceName}"); @@ -367,7 +362,7 @@ private void RenderShapeRefNode(GameObject parent, ScenegraphResourceCollection // Use our groupId if the reference has a local group id. shapeKey = shapeKey.WithGroupID(_resourceAssetKey.GroupID); } - var shape = ContentProvider.Get().GetAsset(shapeKey); + var shape = ContentManager.Instance.GetAsset(shapeKey); // Hold a strong reference to the shape. parent.GetComponent().AddReference(shape); diff --git a/Assets/Scripts/OpenTS2/Components/SimCharacterComponent.cs b/Assets/Scripts/OpenTS2/Components/SimCharacterComponent.cs index d5316d65..9fea0cce 100644 --- a/Assets/Scripts/OpenTS2/Components/SimCharacterComponent.cs +++ b/Assets/Scripts/OpenTS2/Components/SimCharacterComponent.cs @@ -24,16 +24,16 @@ public static SimCharacterComponent CreateNakedBaseSim() { // Load the skeleton, body, hair and face resources. const string skeletonResourceName = "auskel_cres"; - var skeletonAsset = ContentProvider.Get().GetAsset( + var skeletonAsset = ContentManager.Instance.GetAsset( new ResourceKey(skeletonResourceName, GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_CRES)); const string bodyResourceName = "amBodyNaked_cres"; - var bodyAsset = ContentProvider.Get().GetAsset( + var bodyAsset = ContentManager.Instance.GetAsset( new ResourceKey(bodyResourceName, GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_CRES)); const string baldHairResourceName = "amHairBald_cres"; - var baldHairAsset = ContentProvider.Get().GetAsset( + var baldHairAsset = ContentManager.Instance.GetAsset( new ResourceKey(baldHairResourceName, GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_CRES)); const string baseFaceResourceName = "amFace_cres"; - var baseFaceAsset = ContentProvider.Get().GetAsset( + var baseFaceAsset = ContentManager.Instance.GetAsset( new ResourceKey(baseFaceResourceName, GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_CRES)); // Create a scenegraph with all 3 resources. @@ -83,11 +83,13 @@ private void SetupAnimationRig(ScenegraphComponent scene) Scenegraph = scene; var skeleton = Scenegraph.BoneNamesToTransform["auskel"].gameObject; +#if UNITY_EDITOR // Add a bone-renderer so we can visualize the sim's bones. var boneRenderer = skeleton.AddComponent(); var boneTransforms = new List(); GetAllBoneTransformsForVisualization(Scenegraph.BoneNamesToTransform["root_trans"], boneTransforms); boneRenderer.transforms = boneTransforms.ToArray(); +#endif // Add an animator component to the auskel. _animator = skeleton.AddComponent(); @@ -127,6 +129,7 @@ private void SetupAnimationRig(ScenegraphComponent scene) private void AddGizmosAroundInverseKinmaticsPositions() { +#if UNITY_EDITOR // Add some effectors around the foot control points to see what animations should look like. var cubePrimitive = GameObject.CreatePrimitive(PrimitiveType.Cube); var cubeMesh = cubePrimitive.GetComponent().sharedMesh; @@ -153,6 +156,7 @@ private void AddGizmosAroundInverseKinmaticsPositions() new RigEffectorData.Style() { color = new Color(0.0f, 0.8f, 0.4f, 0.5f), size = 0.04f, shape = sphereMesh }); Destroy(spherePrimitive); +#endif } public void AdjustInverseKinematicWeightsForAnimation(AnimResourceConstBlock anim) diff --git a/Assets/Scripts/OpenTS2/Content/BaseLotInfo.cs b/Assets/Scripts/OpenTS2/Content/BaseLotInfo.cs new file mode 100644 index 00000000..7aede48d --- /dev/null +++ b/Assets/Scripts/OpenTS2/Content/BaseLotInfo.cs @@ -0,0 +1,81 @@ +using OpenTS2.Files.Utils; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OpenTS2.Content +{ + public class BaseLotInfo + { + public uint Flags { get; private set; } + public byte LotType { get; private set; } + public string LotName { get; private set; } + public string LotDescription { get; private set; } + public uint Width { get; private set; } + public uint Depth { get; private set; } + public byte RoadsAlongEdges { get; private set; } + public byte CreationFrontEdge { get; private set; } + + public void Read(IoBuffer reader, bool forNeighborhood) + { + string ReadString() + { + // Why is this even different... + if (forNeighborhood) + return reader.ReadUint32PrefixedString(); + else + return reader.ReadVariableLengthPascalString(); + } + var baseLotInfoVersion = reader.ReadUInt16(); + var creationWidth = reader.ReadUInt32(); + var creationDepth = reader.ReadUInt32(); + var lotType = reader.ReadByte(); + var roadsAlongEdges = reader.ReadByte(); + var creationFrontEdge = reader.ReadByte(); + var flags = (baseLotInfoVersion < 5) ? 0 : reader.ReadUInt32(); + var lotName = ""; + var lotDescription = ""; + if (baseLotInfoVersion > 5) + { + lotName = ReadString(); + lotDescription = ReadString(); + } + if (baseLotInfoVersion > 3) + { + var lotHeights = new float[reader.ReadUInt32()]; + for (var i = 0; i < lotHeights.Length; i++) + { + lotHeights[i] = reader.ReadFloat(); + } + } + if (baseLotInfoVersion > 6) + { + var creationRoadHeight = reader.ReadFloat(); + } + if (baseLotInfoVersion > 7) + { + // unknown + reader.ReadUInt32(); + } + if (baseLotInfoVersion == 11) + { + var apartmentCount = reader.ReadByte(); + var apartmentRentalPriceHigh = reader.ReadUInt32(); + var apartmentRentalPriceLow = reader.ReadUInt32(); + var lotClass = reader.ReadUInt32(); + var overrideLotClass = reader.ReadByte(); + } + + Flags = flags; + LotType = lotType; + LotName = lotName; + LotDescription = lotDescription; + Width = creationWidth; + Depth = creationDepth; + RoadsAlongEdges = roadsAlongEdges; + CreationFrontEdge = creationFrontEdge; + } + } +} diff --git a/Assets/Scripts/OpenTS2/Content/BaseLotInfo.cs.meta b/Assets/Scripts/OpenTS2/Content/BaseLotInfo.cs.meta new file mode 100644 index 00000000..d00d7671 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Content/BaseLotInfo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4a0bd18e266ca414b80c25603dada65c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Content/CASManager.cs b/Assets/Scripts/OpenTS2/Content/CASManager.cs new file mode 100644 index 00000000..0bd6767c --- /dev/null +++ b/Assets/Scripts/OpenTS2/Content/CASManager.cs @@ -0,0 +1,32 @@ +using OpenTS2.Common; +using OpenTS2.Content.DBPF; +using OpenTS2.Files.Formats.DBPF; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OpenTS2.Content +{ + public class CASManager + { + public static CASManager Instance { get; private set; } + public bool InCAS = false; + private const string CASLotName = "CAS!"; + private static ResourceKey CASLotKey = new ResourceKey(0, CASLotName, TypeIDs.BASE_LOT_INFO); + + public CASManager() + { + Instance = this; + } + + public void EnterCAS() + { + if (NeighborhoodManager.Instance.CurrentNeighborhood == null) + throw new Exception("Must be in a neighborhood to enter CAS!"); + InCAS = true; + LotManager.Instance.EnterLot(ContentManager.Instance.GetAsset(CASLotKey)); + } + } +} diff --git a/Assets/Scripts/OpenTS2/Content/CASManager.cs.meta b/Assets/Scripts/OpenTS2/Content/CASManager.cs.meta new file mode 100644 index 00000000..d6e2e8d6 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Content/CASManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0ba39d3ce8b1dc04fbe9d81b6634d4f2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Content/CatalogManager.cs b/Assets/Scripts/OpenTS2/Content/CatalogManager.cs index fb824c5b..31d4f830 100644 --- a/Assets/Scripts/OpenTS2/Content/CatalogManager.cs +++ b/Assets/Scripts/OpenTS2/Content/CatalogManager.cs @@ -7,12 +7,7 @@ namespace OpenTS2.Content { public class CatalogManager { - public static CatalogManager Get() - { - return s_instance; - } - - static CatalogManager s_instance; + public static CatalogManager Instance { get; private set; } public List Objects { get @@ -32,12 +27,12 @@ public List Fences Dictionary _entryByGUID = new Dictionary(); Dictionary _fenceByGUID = new Dictionary(); Dictionary _roofByGUID = new Dictionary(); - readonly ContentProvider _provider; + readonly ContentManager _manager; - public CatalogManager(ContentProvider provider) + public CatalogManager() { - s_instance = this; - _provider = provider; + Instance = this; + _manager = ContentManager.Instance; } public void Initialize() @@ -46,19 +41,19 @@ public void Initialize() _fenceByGUID = new Dictionary(); _roofByGUID = new Dictionary(); - var objectList = _provider.GetAssetsOfType(TypeIDs.CATALOG_OBJECT); + var objectList = _manager.GetAssetsOfType(TypeIDs.CATALOG_OBJECT); foreach (CatalogObjectAsset element in objectList) { RegisterObject(element); } - var fenceList = _provider.GetAssetsOfType(TypeIDs.CATALOG_FENCE); + var fenceList = _manager.GetAssetsOfType(TypeIDs.CATALOG_FENCE); foreach (CatalogFenceAsset element in fenceList) { RegisterFence(element); } - var roofList = _provider.GetAssetsOfType(TypeIDs.CATALOG_ROOF); + var roofList = _manager.GetAssetsOfType(TypeIDs.CATALOG_ROOF); foreach (CatalogRoofAsset element in roofList) { RegisterRoof(element); diff --git a/Assets/Scripts/OpenTS2/Content/ContentCache.cs b/Assets/Scripts/OpenTS2/Content/ContentCache.cs index ce5d60ed..10b325b9 100644 --- a/Assets/Scripts/OpenTS2/Content/ContentCache.cs +++ b/Assets/Scripts/OpenTS2/Content/ContentCache.cs @@ -19,25 +19,19 @@ namespace OpenTS2.Content public class CacheKey { public DBPFFile File = null; - public ResourceKey TGI = default(ResourceKey); - private readonly ContentProvider _contentProvider; + public ResourceKey TGI = default; - public CacheKey(ResourceKey tgi, DBPFFile package = null, ContentProvider contentProvider = null) + public CacheKey(ResourceKey tgi, DBPFFile package = null) { - this.TGI = tgi; - this.File = package; - if (contentProvider == null) + TGI = tgi; + File = package; + if (package == null) { - contentProvider = ContentProvider.Get(); + File = ContentManager.Instance.GetEntry(TGI)?.Package; } - this._contentProvider = contentProvider; - if (package == null && this._contentProvider != null) + if (File != null) { - this.File = this._contentProvider.GetEntry(this.TGI)?.Package; - } - if (this.File != null) - { - this.TGI = this.TGI.GlobalGroupID(this.File.GroupID); + TGI = TGI.GlobalGroupID(File.GroupID); } } @@ -73,14 +67,7 @@ public bool Equals(CacheKey obj) public class ContentCache { // Dictionary to contain the temporary cache. - public Dictionary Cache; - public ContentProvider Provider; - - public ContentCache(ContentProvider provider) - { - Provider = provider; - Cache = new Dictionary(); - } + public Dictionary Cache = new Dictionary(); public void Clear() { @@ -90,12 +77,12 @@ public void Clear() public void Remove(ResourceKey key, DBPFFile package) { - Remove(new CacheKey(key, package, Provider)); + Remove(new CacheKey(key, package)); } public void Remove(ResourceKey key) { - Remove(new CacheKey(key, null, Provider)); + Remove(new CacheKey(key, null)); } public void Remove(CacheKey key) @@ -150,7 +137,7 @@ WeakReference GetOrAddInternal(CacheKey key, Func objec /// A strong reference to the cached object. public AbstractAsset GetOrAdd(ResourceKey key, DBPFFile package, Func objectFactory) { - return GetOrAdd(new CacheKey(key, package, Provider), objectFactory); + return GetOrAdd(new CacheKey(key, package), objectFactory); } /// @@ -161,7 +148,7 @@ public AbstractAsset GetOrAdd(ResourceKey key, DBPFFile package, FuncA strong reference to the cached object. public AbstractAsset GetOrAdd(ResourceKey key, Func objectFactory) { - return GetOrAdd(new CacheKey(key, null, Provider), objectFactory); + return GetOrAdd(new CacheKey(key, null), objectFactory); } /// @@ -180,12 +167,12 @@ public AbstractAsset GetOrAdd(CacheKey key, Func object public WeakReference GetWeakReference(ResourceKey key, DBPFFile package) { - return GetWeakReference(new CacheKey(key, package, Provider)); + return GetWeakReference(new CacheKey(key, package)); } public WeakReference GetWeakReference(ResourceKey key) { - return GetWeakReference(new CacheKey(key, null, Provider)); + return GetWeakReference(new CacheKey(key, null)); } public WeakReference GetWeakReference(CacheKey key) diff --git a/Assets/Scripts/OpenTS2/Content/ContentChanges.cs b/Assets/Scripts/OpenTS2/Content/ContentChanges.cs index c078dfd4..660f4d77 100644 --- a/Assets/Scripts/OpenTS2/Content/ContentChanges.cs +++ b/Assets/Scripts/OpenTS2/Content/ContentChanges.cs @@ -9,20 +9,12 @@ namespace OpenTS2.Content { public class ContentChanges { - private readonly ContentProvider _contentProvider; - //private Dictionary m_DeletedPackagesByName = new Dictionary(); - //private List m_DeletedPackages = new List(); - - public ContentChanges(ContentProvider contentProvider) - { - this._contentProvider = contentProvider; - } /// /// Clear all runtime changes made to packages. /// public void Clear() { - var entries = _contentProvider.ContentEntries; + var entries = ContentManager.Instance.ContentEntries; foreach (var element in entries) { if (element.Changes.Dirty) @@ -36,7 +28,7 @@ public void Clear() /// public void SaveChanges() { - var entries = _contentProvider.ContentEntries; + var entries = ContentManager.Instance.ContentEntries; foreach(var element in entries) { if (element.Changes.Dirty) diff --git a/Assets/Scripts/OpenTS2/Content/ContentLoading.cs b/Assets/Scripts/OpenTS2/Content/ContentLoading.cs index 86f76b78..c41194d4 100644 --- a/Assets/Scripts/OpenTS2/Content/ContentLoading.cs +++ b/Assets/Scripts/OpenTS2/Content/ContentLoading.cs @@ -9,14 +9,13 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -using OpenTS2.Client; using OpenTS2.Content.Interfaces; using OpenTS2.Files; namespace OpenTS2.Content { /// - /// Manages loading game content to the provider. + /// Manages loading game content to the manager. /// public static class ContentLoading { @@ -26,9 +25,9 @@ public static class ContentLoading public static void LoadContentStartup() { var startupPackages = Filesystem.GetStartupPackages(); - if (Settings.Get().CustomContentEnabled) + if (GameGlobals.allowCustomContent) startupPackages.AddRange(Filesystem.GetStartupDownloadPackages()); - ContentProvider.Get().AddPackages(startupPackages); + ContentManager.Instance.AddPackages(startupPackages); } /// @@ -39,9 +38,9 @@ public static async Task LoadGameContentAsync(LoadProgress loadProgress) { var gamePackages = Filesystem.GetMainPackages(); gamePackages.AddRange(Filesystem.GetUserPackages()); - if (Settings.Get().CustomContentEnabled) + if (GameGlobals.allowCustomContent) gamePackages.AddRange(Filesystem.GetStreamedDownloadPackages()); - await ContentProvider.Get().AddPackagesAsync(gamePackages, loadProgress); + await ContentManager.Instance.AddPackagesAsync(gamePackages, loadProgress); } /// @@ -51,26 +50,26 @@ public static void LoadGameContentSync() { var gamePackages = Filesystem.GetMainPackages(); gamePackages.AddRange(Filesystem.GetUserPackages()); - if (Settings.Get().CustomContentEnabled) + if (GameGlobals.allowCustomContent) gamePackages.AddRange(Filesystem.GetStreamedDownloadPackages()); - ContentProvider.Get().AddPackages(gamePackages); + ContentManager.Instance.AddPackages(gamePackages); } public static void LoadNeighborhoodContentSync(Neighborhood neighborhood) { var neighborhoodPackages = Filesystem.GetPackagesForNeighborhood(neighborhood); - ContentProvider.Get().AddPackages(neighborhoodPackages); + ContentManager.Instance.AddPackages(neighborhoodPackages); } public static void UnloadNeighborhoodContentSync() { - var contentProvider = ContentProvider.Get(); - var neighborhoodPackages = Filesystem.GetPackagesForNeighborhood(NeighborhoodManager.CurrentNeighborhood); + var contentManager = ContentManager.Instance; + var neighborhoodPackages = Filesystem.GetPackagesForNeighborhood(NeighborhoodManager.Instance.CurrentNeighborhood); foreach(var packagePath in neighborhoodPackages) { - var package = contentProvider.GetPackageByPath(packagePath); + var package = contentManager.GetPackageByPath(packagePath); if (package != null) - contentProvider.RemovePackage(package); + contentManager.RemovePackage(package); } } } diff --git a/Assets/Scripts/OpenTS2/Content/ContentProvider.cs b/Assets/Scripts/OpenTS2/Content/ContentManager.cs similarity index 85% rename from Assets/Scripts/OpenTS2/Content/ContentProvider.cs rename to Assets/Scripts/OpenTS2/Content/ContentManager.cs index ad5371d3..b2ebc08f 100644 --- a/Assets/Scripts/OpenTS2/Content/ContentProvider.cs +++ b/Assets/Scripts/OpenTS2/Content/ContentManager.cs @@ -10,6 +10,7 @@ using OpenTS2.Files.Formats.DBPF; using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Threading.Tasks; @@ -18,24 +19,13 @@ namespace OpenTS2.Content /// /// Provides access to reading and writing to assets in packages. /// - public class ContentProvider : IDisposable + public class ContentManager : IDisposable { - static ContentProvider s_instance; - public static ContentProvider Get() - { - return s_instance; - } - public Dictionary ResourceMap - { - get { return _resourceMap; } - } - public List ContentEntries - { - get { return _contentEntries; } - } + public static ContentManager Instance { get; private set; } + public Dictionary ResourceMap { get; private set; } = new Dictionary(); + public List ContentEntries { get; private set; } = new List(); - private readonly Dictionary _resourceMap = new Dictionary(); - private readonly List _contentEntries = new List(); + private readonly Dictionary _fileMap = new Dictionary(); private readonly Dictionary _entryByGroupID = new Dictionary(); private readonly Dictionary _entryByPath = new Dictionary(); private readonly Dictionary _entryByFile = new Dictionary(); @@ -43,18 +33,39 @@ public List ContentEntries public ContentChanges Changes; public Action OnContentChangedEventHandler; - public ContentProvider() + public ContentManager() + { + Instance = this; + Changes = new ContentChanges(); + Cache = new ContentCache(); + } + + public void MapFileToResource(string path, ResourceKey key) { - s_instance = this; - this.Changes = new ContentChanges(this); - this.Cache = new ContentCache(this); + _fileMap[key] = FileUtils.CleanPath(path); + var entry = new DBPFEntry(); + entry.TGI = key; + ResourceMap[key] = entry; } AbstractAsset InternalLoadAsset(CacheKey key) { - if (key.File == null) - return null; - return key.File.GetAssetByTGI(key.TGI); + if (key.File != null) + { + return key.File.GetAssetByTGI(key.TGI); + } + else + { + if (_fileMap.TryGetValue(key.TGI, out var result)) + { + var codec = Codecs.Get(key.TGI.TypeID); + var fileBytes = File.ReadAllBytes(result); + var asset = codec.Deserialize(fileBytes, key.TGI, null); + asset.TGI = key.TGI; + return asset; + } + } + return null; } /// @@ -64,7 +75,7 @@ AbstractAsset InternalLoadAsset(CacheKey key) /// List of DBPFEntries of specified type. public List GetEntriesOfType(uint typeID) { - return _resourceMap.Where(map => map.Value.GlobalTGI.TypeID == typeID).ToDictionary(x => x.Key, x => x.Value).Values.ToList(); + return ResourceMap.Values.Where(x => x.GlobalTGI.TypeID == typeID).ToList(); } /// @@ -196,7 +207,7 @@ await Task.WhenAll(tasks).ContinueWith((task) => AddPackage(element.file); } loadProgress.Percentage = 1f; - }, TaskScheduler.FromCurrentSynchronizationContext()); + }); } /// @@ -206,7 +217,7 @@ await Task.WhenAll(tasks).ContinueWith((task) => /// Package. public DBPFFile AddPackage(string path) { - path = Filesystem.GetRealPath(path); + path = FileUtils.CleanPath(path); if (_entryByPath.ContainsKey(path)) return _entryByPath[path]; var package = new DBPFFile(path); @@ -216,9 +227,9 @@ public DBPFFile AddPackage(string path) void InternalAddPackage(DBPFFile package) { - package.Provider = this; + package.Manager = this; //Resource map goes from first to last, keeps the first resource it finds with the requested TGI. - _contentEntries.Insert(0, package); + ContentEntries.Insert(0, package); AddToTopOfResourceMap(package); _entryByGroupID[package.GroupID] = package; _entryByPath[package.FilePath] = package; @@ -232,7 +243,7 @@ void InternalAddPackage(DBPFFile package) /// public DBPFEntry GetEntry(ResourceKey key) { - if (_resourceMap.TryGetValue(key, out DBPFEntry output)) + if (ResourceMap.TryGetValue(key, out DBPFEntry output)) return output; return null; } @@ -256,7 +267,7 @@ public void AddToTopOfResourceMap(DBPFFile package) /// Entry to add public void AddToTopOfResourceMap(DBPFEntry entry) { - _resourceMap[entry.GlobalTGI] = entry; + ResourceMap[entry.GlobalTGI] = entry; OnContentChangedEventHandler?.Invoke(entry.GlobalTGI); } @@ -279,11 +290,11 @@ public void UpdateOrAddToResourceMap(DBPFFile package) /// Entry to add to resource map public void UpdateOrAddToResourceMap(DBPFEntry entry) { - if (_resourceMap.TryGetValue(entry.GlobalTGI, out DBPFEntry output)) + if (ResourceMap.TryGetValue(entry.GlobalTGI, out DBPFEntry output)) { if (entry.Package == output.Package) { - _resourceMap[entry.GlobalTGI] = entry; + ResourceMap[entry.GlobalTGI] = entry; } else { @@ -323,11 +334,11 @@ public void RemoveFromResourceMap(DBPFEntry entry) /// Package public void RemoveFromResourceMap(ResourceKey tgi, DBPFFile package) { - if (_resourceMap.TryGetValue(tgi, out DBPFEntry output)) + if (ResourceMap.TryGetValue(tgi, out DBPFEntry output)) { if (package == output.Package) { - _resourceMap.Remove(tgi); + ResourceMap.Remove(tgi); FindEntryForMap(tgi); OnContentChangedEventHandler?.Invoke(tgi); } @@ -340,19 +351,19 @@ public void RemoveFromResourceMap(ResourceKey tgi, DBPFFile package) /// TGI void FindEntryForMap(ResourceKey tgi) { - foreach (var element in _contentEntries) + foreach (var element in ContentEntries) { var localTGI = tgi.GlobalGroupID(element.GroupID); var entryByTGI = element.GetEntryByTGI(localTGI); if (entryByTGI != null) { - _resourceMap[tgi] = entryByTGI; + ResourceMap[tgi] = entryByTGI; return; } entryByTGI = element.GetEntryByTGI(tgi); if (entryByTGI != null) { - _resourceMap[tgi] = entryByTGI; + ResourceMap[tgi] = entryByTGI; return; } } @@ -381,10 +392,10 @@ public void RemovePackage(DBPFFile package) //package.Dispose(); if (_entryByFile.ContainsKey(package)) { - package.Provider = null; + package.Manager = null; RemoveFromResourceMap(package); Cache.RemoveAllForPackage(package); - _contentEntries.Remove(package); + ContentEntries.Remove(package); _entryByGroupID.Remove(package.GroupID); _entryByPath.Remove(package.FilePath); _entryByFile.Remove(package); @@ -425,7 +436,7 @@ public DBPFFile GetPackageByGroup(string groupName) /// Content entry for package. public DBPFFile GetPackageByPath(string path) { - path = Filesystem.GetRealPath(path); + path = FileUtils.CleanPath(path); if (_entryByPath.ContainsKey(path)) return _entryByPath[path]; else @@ -434,7 +445,7 @@ public DBPFFile GetPackageByPath(string path) public void Dispose() { - foreach(var element in _contentEntries) + foreach(var element in ContentEntries) { element.Dispose(); } diff --git a/Assets/Scripts/OpenTS2/Content/ContentProvider.cs.meta b/Assets/Scripts/OpenTS2/Content/ContentManager.cs.meta similarity index 100% rename from Assets/Scripts/OpenTS2/Content/ContentProvider.cs.meta rename to Assets/Scripts/OpenTS2/Content/ContentManager.cs.meta diff --git a/Assets/Scripts/OpenTS2/Content/DBPF/AudioAsset.cs b/Assets/Scripts/OpenTS2/Content/DBPF/AudioAsset.cs index 91066a40..2ed3f656 100644 --- a/Assets/Scripts/OpenTS2/Content/DBPF/AudioAsset.cs +++ b/Assets/Scripts/OpenTS2/Content/DBPF/AudioAsset.cs @@ -9,21 +9,8 @@ namespace OpenTS2.Content.DBPF { - public class AudioAsset : AbstractAsset + public abstract class AudioAsset : AbstractAsset { - public byte[] AudioData; - public AudioClip Clip => _clip; - AudioClip _clip; - public AudioAsset(byte[] data) - { - AudioData = data; - _clip = WAV.ToAudioClip(AudioData, GlobalTGI.ToString()); - } - public override void FreeUnmanagedResources() - { - if (_clip == null) - return; - _clip.Free(); - } + } } diff --git a/Assets/Scripts/OpenTS2/Content/DBPF/BaseLotInfoAsset.cs b/Assets/Scripts/OpenTS2/Content/DBPF/BaseLotInfoAsset.cs new file mode 100644 index 00000000..0f696223 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Content/DBPF/BaseLotInfoAsset.cs @@ -0,0 +1,21 @@ +using OpenTS2.Content; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OpenTS2.Content.DBPF +{ + public class BaseLotInfoAsset : AbstractAsset + { + public string Filename { get; } + public BaseLotInfo BaseLotInfo { get; } + + public BaseLotInfoAsset(string fileName, BaseLotInfo baseLotInfo) + { + Filename = fileName; + BaseLotInfo = baseLotInfo; + } + } +} diff --git a/Assets/Scripts/OpenTS2/Content/DBPF/BaseLotInfoAsset.cs.meta b/Assets/Scripts/OpenTS2/Content/DBPF/BaseLotInfoAsset.cs.meta new file mode 100644 index 00000000..1554f362 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Content/DBPF/BaseLotInfoAsset.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 482d5e4a8de04074da9703b5bc353109 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Content/DBPF/Effects/DecalEffect.cs b/Assets/Scripts/OpenTS2/Content/DBPF/Effects/DecalEffect.cs index a627b7aa..c0631221 100644 --- a/Assets/Scripts/OpenTS2/Content/DBPF/Effects/DecalEffect.cs +++ b/Assets/Scripts/OpenTS2/Content/DBPF/Effects/DecalEffect.cs @@ -22,6 +22,7 @@ public DecalEffect(string textureName, float life, Vector2 textureOffset) public GameObject CreateGameObject() { var gameObject = new GameObject(TextureName, typeof(SwarmDecal), typeof(MeshFilter), typeof(MeshRenderer)); + gameObject.layer = Layers.NonReflective; var swarmDecal = gameObject.GetComponent(); swarmDecal.SetDecal(this); return gameObject; diff --git a/Assets/Scripts/OpenTS2/Content/DBPF/HitListAsset.cs b/Assets/Scripts/OpenTS2/Content/DBPF/HitListAsset.cs new file mode 100644 index 00000000..2ff43b43 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Content/DBPF/HitListAsset.cs @@ -0,0 +1,24 @@ +using OpenTS2.Common; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OpenTS2.Content.DBPF +{ + public class HitListAsset : AudioAsset + { + public ResourceKey[] Sounds; + + public HitListAsset(ResourceKey[] sounds) + { + Sounds = sounds; + } + + public AudioAsset GetRandomAudioAsset() + { + return ContentManager.Instance.GetAsset(Sounds[UnityEngine.Random.Range(0, Sounds.Length)]); + } + } +} diff --git a/Assets/Scripts/OpenTS2/Content/DBPF/HitListAsset.cs.meta b/Assets/Scripts/OpenTS2/Content/DBPF/HitListAsset.cs.meta new file mode 100644 index 00000000..c66d6d9f --- /dev/null +++ b/Assets/Scripts/OpenTS2/Content/DBPF/HitListAsset.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 41443664de41b9a40957eeb12acd4eb8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Content/DBPF/LotInfoAsset.cs b/Assets/Scripts/OpenTS2/Content/DBPF/LotInfoAsset.cs index c3ffa8e0..150d3295 100644 --- a/Assets/Scripts/OpenTS2/Content/DBPF/LotInfoAsset.cs +++ b/Assets/Scripts/OpenTS2/Content/DBPF/LotInfoAsset.cs @@ -5,48 +5,31 @@ /// public class LotInfoAsset : AbstractAsset { + public BaseLotInfo BaseLotInfo { get; } public int LotId { get; } - public uint Flags { get; } - public byte LotType { get; } - public string LotName { get; } - public string LotDescription { get; } - public uint Width { get; } - public uint Depth { get; } - public byte RoadsAlongEdges { get; } public uint LocationX { get; } public uint LocationY { get; } public float NeighborhoodToLotHeightOffset { get; } public byte FrontEdge { get; } - public byte CreationFrontEdge { get; } - - public LotInfoAsset(int lotId, uint flags, byte lotType, string lotName, string lotDescription, - uint width, uint depth, byte roadsAlongEdges, uint locationX, uint locationY, float neighborhoodToLotHeightOffset, - byte creationFrontEdge, byte frontEdge) + public LotInfoAsset(BaseLotInfo baseLotInfo, int lotId, uint locationX, uint locationY, float neighborhoodToLotHeightOffset, byte frontEdge) { + BaseLotInfo = baseLotInfo; LotId = lotId; - Flags = flags; - LotType = lotType; - LotName = lotName; - LotDescription = lotDescription; - Width = width; - Depth = depth; - RoadsAlongEdges = roadsAlongEdges; LocationX = locationX; LocationY = locationY; NeighborhoodToLotHeightOffset = neighborhoodToLotHeightOffset; - CreationFrontEdge = creationFrontEdge; FrontEdge = frontEdge; } public float WorldLocationX => LocationX * NeighborhoodTerrainAsset.TerrainGridSize; public float WorldLocationY => LocationY * NeighborhoodTerrainAsset.TerrainGridSize; - public float WorldWidth => Width * NeighborhoodTerrainAsset.TerrainGridSize; - public float WorldDepth => Depth * NeighborhoodTerrainAsset.TerrainGridSize; + public float WorldWidth => BaseLotInfo.Width * NeighborhoodTerrainAsset.TerrainGridSize; + public float WorldDepth => BaseLotInfo.Depth * NeighborhoodTerrainAsset.TerrainGridSize; public bool HasRoadAlongEdge(LotEdge edge) { - return ((1 << (int)edge) & RoadsAlongEdges) != 0; + return ((1 << (int)edge) & BaseLotInfo.RoadsAlongEdges) != 0; } } diff --git a/Assets/Scripts/OpenTS2/Content/DBPF/LotInfoAsset.cs.meta b/Assets/Scripts/OpenTS2/Content/DBPF/LotInfoAsset.cs.meta index ff008f91..c3c3bfa8 100644 --- a/Assets/Scripts/OpenTS2/Content/DBPF/LotInfoAsset.cs.meta +++ b/Assets/Scripts/OpenTS2/Content/DBPF/LotInfoAsset.cs.meta @@ -1,3 +1,11 @@ -fileFormatVersion: 2 +fileFormatVersion: 2 guid: 377f358f4f4e4c0d9642c6b4a36431c2 -timeCreated: 1690663363 \ No newline at end of file +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Content/DBPF/MP3AudioAsset.cs b/Assets/Scripts/OpenTS2/Content/DBPF/MP3AudioAsset.cs new file mode 100644 index 00000000..ac40832b --- /dev/null +++ b/Assets/Scripts/OpenTS2/Content/DBPF/MP3AudioAsset.cs @@ -0,0 +1,65 @@ +using OpenTS2.Engine; +using OpenTS2.Engine.Audio; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; +using System.IO; +using NAudio; +using NAudio.Wave; +using System.Collections; + +namespace OpenTS2.Content.DBPF +{ + public class MP3AudioAsset : WAVAudioAsset + { + public override AudioClip Clip + { + get + { + if (_clip == null) + { + _clip = AudioClip.Create(GlobalTGI.ToString(), + (int)(_mp3Reader.Length / sizeof(float)), + _sampleProvider.WaveFormat.Channels, + _sampleProvider.WaveFormat.SampleRate, + true, + OnMp3Read, + OnClipPositionSet); + } + return _clip; + } + } + public byte[] AudioData; + private AudioClip _clip; + private Mp3FileReader _mp3Reader; + private ISampleProvider _sampleProvider; + private MemoryStream _stream; + + public MP3AudioAsset(byte[] data) : base(data) + { + _stream = new MemoryStream(data); + _mp3Reader = new Mp3FileReader(_stream); + _sampleProvider = _mp3Reader.ToSampleProvider(); + } + + public override void FreeUnmanagedResources() + { + if (_clip == null) + return; + _clip.Free(); + } + + private void OnMp3Read(float[] data) + { + _sampleProvider.Read(data, 0, data.Length); + } + + private void OnClipPositionSet(int position) + { + _stream.Position = 0; + } + } +} diff --git a/Assets/Scripts/OpenTS2/Content/DBPF/MP3AudioAsset.cs.meta b/Assets/Scripts/OpenTS2/Content/DBPF/MP3AudioAsset.cs.meta new file mode 100644 index 00000000..115f6754 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Content/DBPF/MP3AudioAsset.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e53800fa8f684c94986c08259a43dee8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Content/DBPF/NeighborAsset.cs b/Assets/Scripts/OpenTS2/Content/DBPF/NeighborAsset.cs new file mode 100644 index 00000000..e6612df0 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Content/DBPF/NeighborAsset.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OpenTS2.Content.DBPF +{ + public class NeighborAsset : AbstractAsset + { + public short Id = 0; + public uint GUID; + public ObjectDefinitionAsset ObjectDefinition; + + public NeighborAsset(short neighborId, uint objectGuid) + { + Id = neighborId; + GUID = objectGuid; + ObjectDefinition = ObjectManager.Instance.GetObjectByGUID(GUID); + } + } +} diff --git a/Assets/Scripts/OpenTS2/Content/DBPF/NeighborAsset.cs.meta b/Assets/Scripts/OpenTS2/Content/DBPF/NeighborAsset.cs.meta new file mode 100644 index 00000000..d6623f2b --- /dev/null +++ b/Assets/Scripts/OpenTS2/Content/DBPF/NeighborAsset.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 549e4b3dbafd1ec4eacee33536952c86 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Content/DBPF/ObjectDefinitionAsset.cs b/Assets/Scripts/OpenTS2/Content/DBPF/ObjectDefinitionAsset.cs index f20218c5..5c34df45 100644 --- a/Assets/Scripts/OpenTS2/Content/DBPF/ObjectDefinitionAsset.cs +++ b/Assets/Scripts/OpenTS2/Content/DBPF/ObjectDefinitionAsset.cs @@ -11,8 +11,8 @@ namespace OpenTS2.Content.DBPF public class ObjectDefinitionAsset : AbstractAsset { // TODO: Person and Template object types seem to use 0x80 as the SG instance id for some reason. - public SemiGlobalAsset SemiGlobal => ContentProvider.Get().GetAsset(new ResourceKey(1, GlobalTGI.GroupID, TypeIDs.SEMIGLOBAL)); - public ObjectFunctionsAsset Functions => ContentProvider.Get().GetAsset(new ResourceKey(GlobalTGI.InstanceID, GlobalTGI.GroupID, TypeIDs.OBJF)); + public SemiGlobalAsset SemiGlobal => ContentManager.Instance.GetAsset(new ResourceKey(1, GlobalTGI.GroupID, TypeIDs.SEMIGLOBAL)); + public ObjectFunctionsAsset Functions => ContentManager.Instance.GetAsset(new ResourceKey(GlobalTGI.InstanceID, GlobalTGI.GroupID, TypeIDs.OBJF)); public string FileName; public enum FieldNames diff --git a/Assets/Scripts/OpenTS2/Content/DBPF/ObjectModuleAsset.cs b/Assets/Scripts/OpenTS2/Content/DBPF/ObjectModuleAsset.cs new file mode 100644 index 00000000..2ca033ab --- /dev/null +++ b/Assets/Scripts/OpenTS2/Content/DBPF/ObjectModuleAsset.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; + +namespace OpenTS2.Content.DBPF +{ + /// + /// Called cEdithObjectModule in game. + /// + public class ObjectModuleAsset : AbstractAsset + { + public ObjectModuleAsset(int version, Dictionary objectIdToSaveType) + { + Version = version; + ObjectIdToSaveType = objectIdToSaveType; + } + + public int Version { get; } + + public Dictionary ObjectIdToSaveType { get; } + } +} \ No newline at end of file diff --git a/Assets/Scripts/OpenTS2/Content/DBPF/ObjectModuleAsset.cs.meta b/Assets/Scripts/OpenTS2/Content/DBPF/ObjectModuleAsset.cs.meta new file mode 100644 index 00000000..55092758 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Content/DBPF/ObjectModuleAsset.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 88d31fc370514416b28927df14c0e41d +timeCreated: 1727972177 \ No newline at end of file diff --git a/Assets/Scripts/OpenTS2/Content/DBPF/ObjectSaveTypeTableAsset.cs b/Assets/Scripts/OpenTS2/Content/DBPF/ObjectSaveTypeTableAsset.cs new file mode 100644 index 00000000..d191792e --- /dev/null +++ b/Assets/Scripts/OpenTS2/Content/DBPF/ObjectSaveTypeTableAsset.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; + +namespace OpenTS2.Content.DBPF +{ + /// + /// ObjectSaveTypeTable. Saves "object selectors" which seem to be an abstract identifier for objects, though + /// usually just uses the GUID. + /// + public class ObjectSaveTypeTableAsset : AbstractAsset + { + public List Selectors { get; } + + public ObjectSaveTypeTableAsset(List entries) + { + Selectors = entries; + } + + public readonly struct ObjectSelector + { + public readonly uint objectGuid; + public readonly int saveType; + public readonly string catalogResourceName; + + public ObjectSelector(uint objectGuid, int saveType, string catalogResourceName) + { + this.objectGuid = objectGuid; + this.saveType = saveType; + this.catalogResourceName = catalogResourceName; + } + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/OpenTS2/Content/DBPF/ObjectSaveTypeTableAsset.cs.meta b/Assets/Scripts/OpenTS2/Content/DBPF/ObjectSaveTypeTableAsset.cs.meta new file mode 100644 index 00000000..da7a3d3c --- /dev/null +++ b/Assets/Scripts/OpenTS2/Content/DBPF/ObjectSaveTypeTableAsset.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 323bfccec3124bb2a1ecfe5b1065c919 +timeCreated: 1728009253 \ No newline at end of file diff --git a/Assets/Scripts/OpenTS2/Content/DBPF/Scenegraph/ScenegraphGeometryNodeAsset.cs b/Assets/Scripts/OpenTS2/Content/DBPF/Scenegraph/ScenegraphGeometryNodeAsset.cs index 5230b2e7..c96955a4 100644 --- a/Assets/Scripts/OpenTS2/Content/DBPF/Scenegraph/ScenegraphGeometryNodeAsset.cs +++ b/Assets/Scripts/OpenTS2/Content/DBPF/Scenegraph/ScenegraphGeometryNodeAsset.cs @@ -29,7 +29,7 @@ public ScenegraphModelAsset GetModelAsset(uint groupId = 0) if (groupId != 0) key = key.WithGroupID(groupId); - var model = ContentProvider.Get().GetAsset(key); + var model = ContentManager.Instance.GetAsset(key); Debug.Assert(model != null); return model; } diff --git a/Assets/Scripts/OpenTS2/Content/DBPF/Scenegraph/ScenegraphShapeAsset.cs b/Assets/Scripts/OpenTS2/Content/DBPF/Scenegraph/ScenegraphShapeAsset.cs index 3c9490a0..50ccd72e 100644 --- a/Assets/Scripts/OpenTS2/Content/DBPF/Scenegraph/ScenegraphShapeAsset.cs +++ b/Assets/Scripts/OpenTS2/Content/DBPF/Scenegraph/ScenegraphShapeAsset.cs @@ -51,7 +51,7 @@ public void LoadModelsAndMaterials() for (var i = 0; i < meshes.Count; i++) { var resourceKey = ResourceKey.ScenegraphResourceKey(meshes[i], GlobalTGI.GroupID, TypeIDs.SCENEGRAPH_GMND); - var geometryNode = ContentProvider.Get().GetAsset(resourceKey); + var geometryNode = ContentManager.Instance.GetAsset(resourceKey); Debug.Assert(geometryNode != null, $"Got null geometry for mesh: {meshes[i]}, key: {resourceKey}"); _models[i] = geometryNode.GetModelAsset(GlobalTGI.GroupID); } @@ -61,7 +61,7 @@ public void LoadModelsAndMaterials() foreach (var materialPair in ShapeBlock.Materials) { var materialKey = ResourceKey.ScenegraphResourceKey($"{materialPair.Value}_txmt", GlobalTGI.GroupID, TypeIDs.SCENEGRAPH_TXMT); - var material = ContentProvider.Get().GetAsset(materialKey); + var material = ContentManager.Instance.GetAsset(materialKey); _materials[materialPair.Key] = material; } } diff --git a/Assets/Scripts/OpenTS2/Content/DBPF/Scenegraph/ScenegraphTextureAsset.cs b/Assets/Scripts/OpenTS2/Content/DBPF/Scenegraph/ScenegraphTextureAsset.cs index f734b7ba..bfb746ff 100644 --- a/Assets/Scripts/OpenTS2/Content/DBPF/Scenegraph/ScenegraphTextureAsset.cs +++ b/Assets/Scripts/OpenTS2/Content/DBPF/Scenegraph/ScenegraphTextureAsset.cs @@ -27,10 +27,7 @@ public override void FreeUnmanagedResources() _texture.Free(); } - // TODO: Maybe we should just use `ContentProvider.Get` and compute this eagerly instead of having a - // ContentProvider passed in here. That way we could also drop having to store the full ImageDataBlock - // and just have the more compact Texture2D. - public Texture2D GetSelectedImageAsUnityTexture(ContentProvider provider) + public Texture2D GetSelectedImageAsUnityTexture() { if (_texture != null) { @@ -38,14 +35,14 @@ public Texture2D GetSelectedImageAsUnityTexture(ContentProvider provider) } var subImage = ImageDataBlock.SubImages[ImageDataBlock.SelectedImage]; - _texture = SubImageToTexture(provider, ImageDataBlock.ColorFormat, ImageDataBlock.Width, ImageDataBlock.Height, subImage); + _texture = SubImageToTexture(ImageDataBlock.ColorFormat, ImageDataBlock.Width, ImageDataBlock.Height, subImage); return _texture; } /// /// Compute the full Texture2D with mipmaps using the SubImage data. /// - public static Texture2D SubImageToTexture(ContentProvider provider, ScenegraphTextureFormat colorFormat, int width, int height, SubImage subImage) + public static Texture2D SubImageToTexture(ScenegraphTextureFormat colorFormat, int width, int height, SubImage subImage) { var format = ScenegraphTextureFormatToUnity(colorFormat); var texture = new Texture2D(width, height, format, mipChain: true); @@ -59,7 +56,7 @@ public static Texture2D SubImageToTexture(ContentProvider provider, ScenegraphTe { case LifoReferenceMip lifoReferenceMip: { - var lifoAsset = provider.GetAsset( + var lifoAsset = ContentManager.Instance.GetAsset( new ResourceKey(lifoReferenceMip.LifoName, GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_LIFO)); mipData = lifoAsset.MipData; break; diff --git a/Assets/Scripts/OpenTS2/Content/DBPF/SimsObjectAsset.cs b/Assets/Scripts/OpenTS2/Content/DBPF/SimsObjectAsset.cs new file mode 100644 index 00000000..7fd38536 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Content/DBPF/SimsObjectAsset.cs @@ -0,0 +1,43 @@ +namespace OpenTS2.Content.DBPF +{ + public class SimsObjectAsset : AbstractAsset + { + public SimsObjectAsset(float tileLocationY, float tileLocationX, int level, float elevation, int objectGroupId, + short[] attrs, short[] semiAttrs, short[] temp, short[] data, SimsObjectStackFrame[] stackFrames) + { + TileLocationY = tileLocationY; + TileLocationX = tileLocationX; + Level = level; + Elevation = elevation; + ObjectGroupId = objectGroupId; + Attrs = attrs; + SemiAttrs = semiAttrs; + Temp = temp; + Data = data; + StackFrames = stackFrames; + } + + public float TileLocationY { get; } + public float TileLocationX { get; } + public int Level { get; } + public float Elevation { get; } + public int ObjectGroupId { get; } + + public short[] Attrs { get; } + public short[] SemiAttrs { get; } + public short[] Temp { get; } + public short[] Data { get; } + + public SimsObjectStackFrame[] StackFrames { get; } + } + + public struct SimsObjectStackFrame + { + public ushort ObjectId; + public ushort TreeId; + public ushort BhavSaveType; + + public short[] Params; + public short[] Locals; + } +} \ No newline at end of file diff --git a/Assets/Scripts/OpenTS2/Content/DBPF/SimsObjectAsset.cs.meta b/Assets/Scripts/OpenTS2/Content/DBPF/SimsObjectAsset.cs.meta new file mode 100644 index 00000000..f5d0caea --- /dev/null +++ b/Assets/Scripts/OpenTS2/Content/DBPF/SimsObjectAsset.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: ac6c2c1af0484515b3e9c91dc91159dc +timeCreated: 1727122236 \ No newline at end of file diff --git a/Assets/Scripts/OpenTS2/Content/DBPF/StringSetAsset.cs b/Assets/Scripts/OpenTS2/Content/DBPF/StringSetAsset.cs index f5fd61fd..b42b39b3 100644 --- a/Assets/Scripts/OpenTS2/Content/DBPF/StringSetAsset.cs +++ b/Assets/Scripts/OpenTS2/Content/DBPF/StringSetAsset.cs @@ -10,7 +10,6 @@ using System.Text; using System.Threading.Tasks; using OpenTS2.Files.Formats.DBPF; -using OpenTS2.Client; namespace OpenTS2.Content.DBPF { @@ -122,12 +121,12 @@ public StringSetAsset(StringSetData stringData) /// Localized string public string GetString(int id) { - return _stringData.GetString(id, Settings.Get().Language); + return _stringData.GetString(id, GameGlobals.Instance.Language); } public string GetDescription(int id) { - return _stringData.GetDescription(id, Settings.Get().Language); + return _stringData.GetDescription(id, GameGlobals.Instance.Language); } /// @@ -138,7 +137,7 @@ public string GetDescription(int id) /// Language of string to replace. public void SetString(string str, int id) { - var lang = Settings.Get().Language; + var lang = GameGlobals.Instance.Language; if (!StringData.HasLanguage(lang)) lang = Languages.USEnglish; StringData.SetString(str, id, lang); diff --git a/Assets/Scripts/OpenTS2/Content/DBPF/WAVAudioAsset.cs b/Assets/Scripts/OpenTS2/Content/DBPF/WAVAudioAsset.cs new file mode 100644 index 00000000..252afb93 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Content/DBPF/WAVAudioAsset.cs @@ -0,0 +1,45 @@ +using OpenTS2.Engine; +using OpenTS2.Engine.Audio; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace OpenTS2.Content.DBPF +{ + public class WAVAudioAsset : AudioAsset + { + public virtual AudioClip Clip + { + get + { + if (_clip == null) + _clip = WAV.ToAudioClip(Data, GlobalTGI.ToString()); + return _clip; + } + } + protected byte[] Data; + private AudioClip _clip; + + public WAVAudioAsset(byte[] data) + { + Data = data; + } + + public override void FreeUnmanagedResources() + { + if (_clip == null) + return; + _clip.Free(); + } + +#if UNITY_EDITOR + public byte[] GetWAVData() + { + return Data; + } +#endif + } +} diff --git a/Assets/Scripts/OpenTS2/Content/DBPF/WAVAudioAsset.cs.meta b/Assets/Scripts/OpenTS2/Content/DBPF/WAVAudioAsset.cs.meta new file mode 100644 index 00000000..72374446 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Content/DBPF/WAVAudioAsset.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ba44f409dd88e7843a5a8a11ac5d9547 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Content/DBPF/WallGraphAsset.cs b/Assets/Scripts/OpenTS2/Content/DBPF/WallGraphAsset.cs index f3720d79..5b3299bd 100644 --- a/Assets/Scripts/OpenTS2/Content/DBPF/WallGraphAsset.cs +++ b/Assets/Scripts/OpenTS2/Content/DBPF/WallGraphAsset.cs @@ -1,4 +1,7 @@ +using System; using System.Collections.Generic; +using System.Linq; +using UnityEngine; namespace OpenTS2.Content.DBPF { @@ -31,11 +34,12 @@ public class WallGraphAsset : AbstractAsset { public int Width { get; } public int Height { get; } - public int Floors { get; } + public int Floors { get; private set; } public int BaseFloor { get; } public Dictionary Positions { get; } public int[] Rooms { get; } - public WallGraphLineEntry[] Lines { get; } + public WallGraphLineEntry[] Lines { get => _lines; set => _lines = value; } + private WallGraphLineEntry[] _lines; public WallGraphAsset(int width, int height, int floors, int baseFloor, WallGraphPositionEntry[] pos, int[] rooms, WallGraphLineEntry[] lines) { @@ -59,6 +63,126 @@ private Dictionary ToPositionDictionary(WallGraphPo return result; } - } + bool getJuncIdByPosition(Vector2 Position, int Floor, out int juncId, bool createIfNull = true) + { + bool existed = false; + var junctions = Positions.Where(x => x.Value.XPos == Position.x && x.Value.YPos == Position.y && x.Value.Level == Floor); + juncId = -1; + if (junctions.Any()) + { + juncId = junctions.First().Key; // found a matching position + existed = true; + } + else if (createIfNull) + { // make a new position + if (Positions.Any()) + juncId = Positions.Select(x => x.Key).Max() + 1; + else juncId = 0; + Positions.Add(juncId, new WallGraphPositionEntry() + { + Id = juncId, + Level = Floor, + XPos = Position.x, + YPos = Position.y, + }); + } + return existed; + } + + public bool PushWall(Vector2 Pos1, Vector2 Pos2, int Floor, out int LayerID) + { + LayerID = -1; + + bool fromExistedAlready = getJuncIdByPosition(Pos1, Floor, out int fromId); + if (fromId == -1) // unable to create !! + return false; + bool toExistedAlready = getJuncIdByPosition(Pos2, Floor, out int toId); + if (toId == -1) // unable to create !! + return false; + if (fromExistedAlready && toExistedAlready) + { // wall may already exist + bool exists = _lines.Any(x => x.ToId == toId && x.FromId == fromId); // check if this wall segment exists + if (exists) + return false; // this wall segment already exists. + exists = _lines.Any(x => x.ToId == fromId && x.FromId == toId); + if (exists) + return false; // this wall segment already exists. + } + + int layerId = 99; + if(_lines.Any()) layerId = _lines.Select(x => x.LayerId).Max() + 1; + + Array.Resize(ref _lines, Lines.Length + 1); + WallGraphLineEntry line = new WallGraphLineEntry() + { + FromId = fromId, + LayerId = layerId, + ToId = toId, + }; + _lines[_lines.Length - 1] = line; + LayerID = layerId; + if (Floors <= Floor) + Floors++; + return true; + } + + private void _delWall(int index) + { + int i = index; + //found the wall + if (i != _lines.Length - 1) // last wall + _lines[i] = _lines[_lines.Length - 1]; // move last line to this spot + Array.Resize(ref _lines, _lines.Length - 1); // shorten array by one + } + + internal bool RemoveWall(Vector2 From, Vector2 To, int Floor, out int LayerID) + { // should be refactored to batch delete a set of segments instead of one at a time due to iterations being potentially large + LayerID = -1; + + getJuncIdByPosition(From, Floor, out int fromId, false); + if (fromId == -1) // wall index doesn't exist? + return false; + getJuncIdByPosition(To, Floor, out int toId, false); + if (toId == -1) // wall index doesn't exist? + return false; + + for (int i = _lines.Length - 1; i >= 0; i--) // reverse order -- since players may more often delete walls they just made + { + var line = _lines[i]; + + if (toId == fromId) throw new Exception("From and To IDs are the same!"); + if (line.ToId != toId && line.ToId != fromId) continue; + if (line.FromId != toId && line.FromId != fromId) continue; + + _delWall(i); + LayerID = line.LayerId; + return true; + } + return false; // not found + } + /// + /// Deletes all the wall lines from the selected floor by their LayerID. + /// + /// + /// + /// + internal int RemoveWalls(params int[] WallLayerIDs) + { + int index = -1; + int found = 0; + HashSet deletionIndices = new HashSet(); + foreach(var line in _lines) + { + index++; + if (!WallLayerIDs.Contains(line.LayerId)) continue; + found++; + deletionIndices.Add(index); + } + int deleted = 0; + foreach (int i in deletionIndices) + _delWall(i - deleted++); + return deleted; + } + } } \ No newline at end of file diff --git a/Assets/Scripts/OpenTS2/Content/EPManager.cs b/Assets/Scripts/OpenTS2/Content/EPManager.cs index 0f5a26ec..4ea85381 100644 --- a/Assets/Scripts/OpenTS2/Content/EPManager.cs +++ b/Assets/Scripts/OpenTS2/Content/EPManager.cs @@ -10,29 +10,14 @@ namespace OpenTS2.Content { public class EPManager { - public static EPManager Get() - { - return s_instance; - } - static EPManager s_instance; + public static EPManager Instance { get; private set; } - public int InstalledProducts - { - get - { - return _installedProducts; - } - set - { - _installedProducts = value; - } - } + // All products + public int InstalledProducts { get; set; } = 0x3FFFF; - //mask of all products - int _installedProducts = 0x3FFFF; public EPManager() { - s_instance = this; + Instance = this; } public EPManager(int installedProducts) : this() { @@ -51,7 +36,7 @@ public static List GetProductsInMask(int productMask) } public bool IsEPInstalled(ProductFlags product) { - if (BitUtils.AllBitsSet(_installedProducts, (int)product)) + if (BitUtils.AllBitsSet(InstalledProducts, (int)product)) return true; return false; } diff --git a/Assets/Scripts/OpenTS2/Content/EffectsManager.cs b/Assets/Scripts/OpenTS2/Content/EffectsManager.cs index 8421849e..13f74d76 100644 --- a/Assets/Scripts/OpenTS2/Content/EffectsManager.cs +++ b/Assets/Scripts/OpenTS2/Content/EffectsManager.cs @@ -1,5 +1,6 @@ using OpenTS2.Common; using OpenTS2.Content.DBPF; +using OpenTS2.Engine; using OpenTS2.Files; using OpenTS2.Files.Formats.DBPF; using OpenTS2.Scenes.ParticleEffects; @@ -9,31 +10,29 @@ namespace OpenTS2.Content { public class EffectsManager { - private static EffectsManager _instance; + [GameProperty(false)] + public static bool EnableEffects = true; + public static EffectsManager Instance { get; set; } - public static EffectsManager Get() + public EffectsManager() { - return _instance; - } - - public EffectsManager(ContentProvider provider) - { - _instance = this; - _provider = provider; + Instance = this; + _manager = ContentManager.Instance; + Core.OnFinishedLoading += Initialize; } private EffectsAsset _effects; - private readonly ContentProvider _provider; + private readonly ContentManager _manager; public bool Ready { get; private set; } public void Initialize() { // Load effects package. - _provider.AddPackages( - Filesystem.GetPackagesInDirectory(Filesystem.GetDataPathForProduct(ProductFlags.BaseGame) + - "/Res/Effects")); - _effects = _provider.GetAsset(new ResourceKey(instanceID: 1, groupID: GroupIDs.Effects, + _manager.AddPackages( + Filesystem.GetPackagesInDirectory(Filesystem.GetPathForProduct(ProductFlags.BaseGame) + + "TSData/Res/Effects")); + _effects = _manager.GetAsset(new ResourceKey(instanceID: 1, groupID: GroupIDs.Effects, typeID: TypeIDs.EFFECTS)); Debug.Assert(_effects != null, "Couldn't find effects"); @@ -47,6 +46,8 @@ public bool HasEffect(string effectName) public SwarmParticleSystem CreateEffect(string effectName) { + if (!EnableEffects) return null; + var visualEffect = _effects.GetEffectByName(effectName); var system = new GameObject("SwarmParticleSystem", typeof(ParticleSystem), typeof(SwarmParticleSystem)); diff --git a/Assets/Scripts/OpenTS2/Content/GameGlobals.cs b/Assets/Scripts/OpenTS2/Content/GameGlobals.cs new file mode 100644 index 00000000..1fbf6e9e --- /dev/null +++ b/Assets/Scripts/OpenTS2/Content/GameGlobals.cs @@ -0,0 +1,22 @@ +using OpenTS2.Engine; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OpenTS2.Content +{ + public class GameGlobals + { + [GameProperty(true)] + public static bool allowCustomContent = true; + public static GameGlobals Instance { get; private set; } + public Languages Language = Languages.USEnglish; + + public GameGlobals() + { + Instance = this; + } + } +} diff --git a/Assets/Scripts/OpenTS2/Content/GameGlobals.cs.meta b/Assets/Scripts/OpenTS2/Content/GameGlobals.cs.meta new file mode 100644 index 00000000..79bc79ab --- /dev/null +++ b/Assets/Scripts/OpenTS2/Content/GameGlobals.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ffc224d4eacdb4146b206da78a52f703 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Content/Interfaces/IPathProvider.cs b/Assets/Scripts/OpenTS2/Content/Interfaces/IPathProvider.cs index 85fe0245..759ca0a4 100644 --- a/Assets/Scripts/OpenTS2/Content/Interfaces/IPathProvider.cs +++ b/Assets/Scripts/OpenTS2/Content/Interfaces/IPathProvider.cs @@ -16,7 +16,7 @@ namespace OpenTS2.Content.Interfaces /// /// Interface for providing paths to the game's user data and game folders. /// - public interface IPathProvider + public interface IPathManager { public string GetPathForProduct(ProductFlags productFlag); public string GetDataPathForProduct(ProductFlags productFlag); diff --git a/Assets/Scripts/OpenTS2/Client/Languages.cs b/Assets/Scripts/OpenTS2/Content/Languages.cs similarity index 95% rename from Assets/Scripts/OpenTS2/Client/Languages.cs rename to Assets/Scripts/OpenTS2/Content/Languages.cs index d7bf5d1b..24694110 100644 --- a/Assets/Scripts/OpenTS2/Client/Languages.cs +++ b/Assets/Scripts/OpenTS2/Content/Languages.cs @@ -4,7 +4,7 @@ using System.Text; using System.Threading.Tasks; -namespace OpenTS2.Client +namespace OpenTS2.Content { public enum Languages : byte { diff --git a/Assets/Scripts/OpenTS2/Client/Languages.cs.meta b/Assets/Scripts/OpenTS2/Content/Languages.cs.meta similarity index 100% rename from Assets/Scripts/OpenTS2/Client/Languages.cs.meta rename to Assets/Scripts/OpenTS2/Content/Languages.cs.meta diff --git a/Assets/Scripts/OpenTS2/Content/Layers.cs b/Assets/Scripts/OpenTS2/Content/Layers.cs new file mode 100644 index 00000000..223cc948 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Content/Layers.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OpenTS2.Content +{ + public static class Layers + { + public const int Default = 0; + public const int TransparentFX = 1; + public const int IgnoreRaycast = 2; + public const int Terrain = 3; + public const int Water = 4; + public const int UI = 5; + public const int NonReflective = 6; + } +} diff --git a/Assets/Scripts/OpenTS2/Content/Layers.cs.meta b/Assets/Scripts/OpenTS2/Content/Layers.cs.meta new file mode 100644 index 00000000..dbedcca0 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Content/Layers.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1693963615322f04cabcd1e5d74ef577 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Content/Lot.cs b/Assets/Scripts/OpenTS2/Content/Lot.cs index 824e796c..baa880a8 100644 --- a/Assets/Scripts/OpenTS2/Content/Lot.cs +++ b/Assets/Scripts/OpenTS2/Content/Lot.cs @@ -23,7 +23,7 @@ public class Lot /// public string LotPackagePath { get; } - private DBPFFile Package => ContentProvider.Get().GetPackageByPath(LotPackagePath); + private DBPFFile Package => ContentManager.Instance.GetPackageByPath(LotPackagePath); public Lot(LotInfoAsset lotInfo, string lotPackage) { @@ -51,7 +51,7 @@ public GameObject CreateLotImposter() var gameObject = imposter.CreateRootGameObject(); // Rotate based on the whether the frontEdge has changed from the lot's creation time. - var rotation = (_lotInfo.CreationFrontEdge - _lotInfo.FrontEdge) * -90; + var rotation = (_lotInfo.BaseLotInfo.CreationFrontEdge - _lotInfo.FrontEdge) * -90; // Lot imposters are always stored rotated as per their CreationFrontEdge. So a lot facing a road in the // positive x direction, i.e the "front" of the house is towards positive y will have its imposter model @@ -60,7 +60,7 @@ public GameObject CreateLotImposter() // However, regardless of rotation, a lot in the neighborhood is stored with its grid coordinates // corresponding to the bottom-right of the grid. Thus when a lot is rotated, we need to rotate the imposter // from the correct pivot point. - var frontEdgeDiff = (_lotInfo.CreationFrontEdge - _lotInfo.FrontEdge) % 4; + var frontEdgeDiff = (_lotInfo.BaseLotInfo.CreationFrontEdge - _lotInfo.FrontEdge) % 4; Vector3 pivot; if (frontEdgeDiff == 0) // No rotation. @@ -74,7 +74,7 @@ public GameObject CreateLotImposter() else throw new IndexOutOfRangeException(); - var position = new GameObject($"imposter_position_{_lotInfo.LotName}") + var position = new GameObject($"imposter_position_{_lotInfo.BaseLotInfo.LotName}") { transform = { diff --git a/Assets/Scripts/OpenTS2/Content/LotManager.cs b/Assets/Scripts/OpenTS2/Content/LotManager.cs new file mode 100644 index 00000000..204625d9 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Content/LotManager.cs @@ -0,0 +1,33 @@ +using OpenTS2.Content.DBPF; +using OpenTS2.Engine; +using OpenTS2.Game; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OpenTS2.Content +{ + public class LotManager + { + public static LotManager Instance { get; private set; } + + public LotManager() + { + Instance = this; + } + + public void EnterLot(BaseLotInfoAsset baseLotInfo) + { + if (NeighborhoodManager.Instance.CurrentNeighborhood == null) + throw new Exception("Must be in a neighborhood to enter a lot"); + ContentManager.Instance.Changes.SaveChanges(); + Core.OnLotLoaded?.Invoke(); + var simulator = Simulator.Instance; + if (simulator != null) + simulator.Kill(); + var lotSimulator = Simulator.Create(Simulator.Context.Lot); + } + } +} diff --git a/Assets/Scripts/OpenTS2/Content/LotManager.cs.meta b/Assets/Scripts/OpenTS2/Content/LotManager.cs.meta new file mode 100644 index 00000000..464a3d7e --- /dev/null +++ b/Assets/Scripts/OpenTS2/Content/LotManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f75a889520a01ab4ab79d582b5a36e66 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Content/NeighborManager.cs b/Assets/Scripts/OpenTS2/Content/NeighborManager.cs new file mode 100644 index 00000000..66fb4622 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Content/NeighborManager.cs @@ -0,0 +1,43 @@ +using OpenTS2.Content.DBPF; +using OpenTS2.Files.Formats.DBPF; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace OpenTS2.Content +{ + public class NeighborManager : MonoBehaviour + { + public static NeighborManager Instance { get; private set; } + public Dictionary NeighborById; + public List Neighbors => NeighborById.Values.ToList(); + private ContentManager _contentManager; + + public void Initialize() + { + var currentNeighborhood = NeighborhoodManager.Instance.CurrentNeighborhood; + _contentManager = ContentManager.Instance; + NeighborById = new Dictionary(); + var neighborEntries = _contentManager.ResourceMap.Values.Where(x => x.GlobalTGI.TypeID == TypeIDs.NEIGHBOR && x.GlobalTGI.GroupID == currentNeighborhood.GroupID); + foreach(var neighborEntry in neighborEntries) + { + var neighbor = neighborEntry.GetAsset(); + NeighborById[neighbor.Id] = neighbor; + } + } + + public static void Create() + { + if (Instance != null) + { + Destroy(Instance.gameObject); + } + var go = new GameObject("Neighbor Manager"); + Instance = go.AddComponent(); + Instance.Initialize(); + } + } +} diff --git a/Assets/Scripts/OpenTS2/Content/NeighborManager.cs.meta b/Assets/Scripts/OpenTS2/Content/NeighborManager.cs.meta new file mode 100644 index 00000000..788eecd1 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Content/NeighborManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4085ccb5fb653d64cbdf92bf12286119 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Content/Neighborhood.cs b/Assets/Scripts/OpenTS2/Content/Neighborhood.cs index 5f36ea2b..c977bf99 100644 --- a/Assets/Scripts/OpenTS2/Content/Neighborhood.cs +++ b/Assets/Scripts/OpenTS2/Content/Neighborhood.cs @@ -1,5 +1,4 @@ -using OpenTS2.Client; -using OpenTS2.Common; +using OpenTS2.Common; using OpenTS2.Content.DBPF; using OpenTS2.Files; using OpenTS2.Files.Formats.DBPF; @@ -15,9 +14,9 @@ namespace OpenTS2.Content { public class Neighborhood { - public NeighborhoodDecorationsAsset Decorations => ContentProvider.Get() + public NeighborhoodDecorationsAsset Decorations => ContentManager.Instance .GetAsset(new ResourceKey(0, GroupID, TypeIDs.NHOOD_DECORATIONS)); - public NeighborhoodTerrainAsset Terrain => ContentProvider.Get().GetAsset(new ResourceKey(0, GroupID, TypeIDs.NHOOD_TERRAIN)); + public NeighborhoodTerrainAsset Terrain => ContentManager.Instance.GetAsset(new ResourceKey(0, GroupID, TypeIDs.NHOOD_TERRAIN)); public Type NeighborhoodType => _info.NeighborhoodType; public string Prefix => _info.MainPrefix; public string PackageFilePath => _info.Package.FilePath; @@ -42,9 +41,9 @@ public enum Type public Neighborhood(NeighborhoodInfoAsset infoAsset) { _info = infoAsset; - var contentProvider = ContentProvider.Get(); + var contentManager = ContentManager.Instance; var stringSetKey = new ResourceKey(1, GroupID, TypeIDs.CTSS); - _stringSet = contentProvider.GetAsset(stringSetKey); + _stringSet = contentManager.GetAsset(stringSetKey); _thumbnail = new Texture2D(1, 1); var thumbnailPath = Path.ChangeExtension(PackageFilePath, ".png"); if (File.Exists(thumbnailPath)) diff --git a/Assets/Scripts/OpenTS2/Content/NeighborhoodManager.cs b/Assets/Scripts/OpenTS2/Content/NeighborhoodManager.cs index 9a144f2d..e5b6461d 100644 --- a/Assets/Scripts/OpenTS2/Content/NeighborhoodManager.cs +++ b/Assets/Scripts/OpenTS2/Content/NeighborhoodManager.cs @@ -12,41 +12,50 @@ using UnityEngine; using UnityEngine.SceneManagement; using OpenTS2.Rendering; +using OpenTS2.Engine; +using OpenTS2.Game; namespace OpenTS2.Content { - public static class NeighborhoodManager + public class NeighborhoodManager { - public static Dictionary NeighborhoodObjects = new Dictionary(); + public static NeighborhoodManager Instance { get; private set; } + public Dictionary NeighborhoodObjects { get; private set; } + public List Neighborhoods { get; private set; } - public static Neighborhood CurrentNeighborhood = null; - public static List Neighborhoods => _neighborHoods; - static List _neighborHoods = new List(); - public static void Initialize() + public Neighborhood CurrentNeighborhood = null; + public NeighborhoodManager() { - _neighborHoods.Clear(); - var contentProvider = ContentProvider.Get(); - var allInfos = contentProvider.GetAssetsOfType(TypeIDs.NHOOD_INFO); - foreach(var ninfo in allInfos) + Instance = this; + Core.OnFinishedLoading += OnFinishedLoading; + } + + private void OnFinishedLoading() + { + Neighborhoods = new List(); + NeighborhoodObjects = new Dictionary(); + var contentManager = ContentManager.Instance; + var allInfos = contentManager.GetAssetsOfType(TypeIDs.NHOOD_INFO); + foreach (var ninfo in allInfos) { var nhood = new Neighborhood(ninfo); - _neighborHoods.Add(nhood); + Neighborhoods.Add(nhood); } // Create a mapping of GUID -> cres files for neighborhood objects. - var hoodObjects = contentProvider.GetAssetsOfType(TypeIDs.NHOOD_OBJECT); + var hoodObjects = contentManager.GetAssetsOfType(TypeIDs.NHOOD_OBJECT); foreach (var objectAsset in hoodObjects) { NeighborhoodObjects[objectAsset.Guid] = objectAsset.ModelName; } } - public static void LeaveNeighborhood() + public void LeaveNeighborhood() { Cursor.visible = true; Cursor.lockState = CursorLockMode.None; CursorController.Cursor = CursorController.CursorType.Hourglass; - ContentProvider.Get().Changes.SaveChanges(); + ContentManager.Instance.Changes.SaveChanges(); if (CurrentNeighborhood != null) ContentLoading.UnloadNeighborhoodContentSync(); CurrentNeighborhood = null; @@ -54,14 +63,13 @@ public static void LeaveNeighborhood() CursorController.Cursor = CursorController.CursorType.Default; } - public static void EnterNeighborhood(Neighborhood neighborhood) + public void EnterNeighborhood(Neighborhood neighborhood) { CursorController.Cursor = CursorController.CursorType.Hourglass; - ContentProvider.Get().Changes.SaveChanges(); + ContentManager.Instance.Changes.SaveChanges(); if (CurrentNeighborhood != null) ContentLoading.UnloadNeighborhoodContentSync(); ContentLoading.LoadNeighborhoodContentSync(neighborhood); - MusicController.FadeOutMusic(); CurrentNeighborhood = neighborhood; SceneManager.LoadScene("Neighborhood"); CursorController.Cursor = CursorController.CursorType.Default; diff --git a/Assets/Scripts/OpenTS2/Content/ObjectManager.cs b/Assets/Scripts/OpenTS2/Content/ObjectManager.cs index 2876a0ae..4a133cc6 100644 --- a/Assets/Scripts/OpenTS2/Content/ObjectManager.cs +++ b/Assets/Scripts/OpenTS2/Content/ObjectManager.cs @@ -1,59 +1,50 @@ using OpenTS2.Common; using OpenTS2.Content.DBPF; +using OpenTS2.Engine; using OpenTS2.Files.Formats.DBPF; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using UnityEngine; namespace OpenTS2.Content { - public class ObjectManager + public class ObjectManager : MonoBehaviour { - public static ObjectManager Get() - { - return s_instance; - } - - static ObjectManager s_instance; - public List Objects - { - get - { - return _objectByGUID.Values.ToList(); - } - } - - Dictionary _objectByGUID = new Dictionary(); - readonly ContentProvider _provider; - - public ObjectManager(ContentProvider provider) - { - s_instance = this; - _provider = provider; - } + public static ObjectManager Instance { get; private set; } + public Dictionary ObjectByGUID; + public List Objects => ObjectByGUID.Values.ToList(); + private ContentManager _contentManager; public void Initialize() { - _objectByGUID = new Dictionary(); - var objectList = _provider.GetAssetsOfType(TypeIDs.OBJD); - foreach(ObjectDefinitionAsset element in objectList) + _contentManager = ContentManager.Instance; + ObjectByGUID = new Dictionary(); + var objects = _contentManager.GetAssetsOfType(TypeIDs.OBJD); + foreach (var objd in objects) { - RegisterObject(element); + ObjectByGUID[objd.GUID] = objd; } } - void RegisterObject(ObjectDefinitionAsset objd) + public ObjectDefinitionAsset GetObjectByGUID(uint guid) { - _objectByGUID[objd.GUID] = objd; + if (ObjectByGUID.TryGetValue(guid, out var objd)) + return objd; + return null; } - public ObjectDefinitionAsset GetObjectByGUID(uint guid) + public static void Create() { - if (_objectByGUID.TryGetValue(guid, out ObjectDefinitionAsset obj)) - return obj; - return null; + if (Instance != null) + { + Destroy(Instance.gameObject); + } + var go = new GameObject("Object Manager"); + Instance = go.AddComponent(); + Instance.Initialize(); } } } diff --git a/Assets/Scripts/OpenTS2/Content/TerrainManager.cs b/Assets/Scripts/OpenTS2/Content/TerrainManager.cs index 1fbaa815..f74ca025 100644 --- a/Assets/Scripts/OpenTS2/Content/TerrainManager.cs +++ b/Assets/Scripts/OpenTS2/Content/TerrainManager.cs @@ -11,7 +11,7 @@ namespace OpenTS2.Content { public static class TerrainManager { - private static Dictionary s_terrainTypes = new Dictionary(); + private static Dictionary TerrainTypes = new Dictionary(); public static void Initialize() { var temperate = new TerrainType @@ -75,12 +75,12 @@ public static void Initialize() public static void RegisterTerrainType(TerrainType type) { - s_terrainTypes[type.Name] = type; + TerrainTypes[type.Name] = type; } public static TerrainType GetTerrainType(string key) { - if (!s_terrainTypes.TryGetValue(key, out TerrainType result)) + if (!TerrainTypes.TryGetValue(key, out TerrainType result)) throw new KeyNotFoundException($"Can't find terrain type {key}"); return result; } diff --git a/Assets/Scripts/OpenTS2/DBPFSharp/QfsCompression.cs b/Assets/Scripts/OpenTS2/DBPFSharp/QfsCompression.cs index 55d4b238..e4daddc2 100644 --- a/Assets/Scripts/OpenTS2/DBPFSharp/QfsCompression.cs +++ b/Assets/Scripts/OpenTS2/DBPFSharp/QfsCompression.cs @@ -78,7 +78,7 @@ internal static class QfsCompression /// If set to true prefix the size of the compressed data, as is used by SC4; otherwise false. /// A byte array containing the compressed data or null if the data cannot be compressed. /// is null. - public static byte[]? Compress(byte[] input, bool prefixLength) + public static byte[] Compress(byte[] input, bool prefixLength) { if (input == null) { @@ -418,7 +418,7 @@ int Log2(uint n) /// /// This method has been adapted from deflate.c in zlib version 1.2.3. /// - public byte[]? Compress() + public byte[] Compress() { this.hash = input[0]; this.hash = ((this.hash << hashShift) ^ input[1]) & hashMask; diff --git a/Assets/Scripts/OpenTS2/Diagnostic/BoolpropCheat.cs b/Assets/Scripts/OpenTS2/Diagnostic/BoolpropCheat.cs new file mode 100644 index 00000000..85c002ac --- /dev/null +++ b/Assets/Scripts/OpenTS2/Diagnostic/BoolpropCheat.cs @@ -0,0 +1,42 @@ +using OpenTS2.Diagnostic; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Unity.Plastic.Newtonsoft.Json; +using UnityEngine; + +/// +/// Houses some common TS2 boolean properties +/// + +namespace Assets.Scripts.OpenTS2.Diagnostic +{ + public class SimpleProperty : IConsoleProperty + { + string serializedValue + { + get => Convert.ToString(myValue); + set => myValue = (T)Convert.ChangeType(value, typeof(T)); + } + + T myValue; + + public SimpleProperty() + { + } + public SimpleProperty(T DefaultValue) : this() + { + myValue = DefaultValue; + } + + public string GetStringValue() => serializedValue; + public Type GetValueType() => typeof(T); + public void SetStringValue(string value) => serializedValue = value; + + public static SimpleProperty Create() => new SimpleProperty(); + public static SimpleProperty Create(T DefaultValue) => new SimpleProperty(DefaultValue); + } +} diff --git a/Assets/Scripts/OpenTS2/Diagnostic/BoolpropCheat.cs.meta b/Assets/Scripts/OpenTS2/Diagnostic/BoolpropCheat.cs.meta new file mode 100644 index 00000000..c0990ca2 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Diagnostic/BoolpropCheat.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fc38f22d7f39dcf45b82f46e2f6f4abc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Diagnostic/CheatConsoleController.cs b/Assets/Scripts/OpenTS2/Diagnostic/CheatConsoleController.cs index 392c213e..149100e4 100644 --- a/Assets/Scripts/OpenTS2/Diagnostic/CheatConsoleController.cs +++ b/Assets/Scripts/OpenTS2/Diagnostic/CheatConsoleController.cs @@ -11,7 +11,7 @@ namespace OpenTS2.Diagnostic /// public class CheatConsoleController : MonoBehaviour, IConsoleOutput { - private static CheatConsoleController s_singleton = null; + public static CheatConsoleController Instance { get; private set; } public GameObject ConsoleParent; public InputField CheatInputField; public Text ConsoleOutput; @@ -24,13 +24,8 @@ public class CheatConsoleController : MonoBehaviour, IConsoleOutput private void Awake() { - if (s_singleton != null) - { - Destroy(gameObject); - return; - } + Instance = this; CheatInputField.onValueChanged.AddListener(OnTextChanged); - s_singleton = this; ConsoleParent.SetActive(false); DontDestroyOnLoad(this); } diff --git a/Assets/Scripts/OpenTS2/Diagnostic/CheatSystem.cs b/Assets/Scripts/OpenTS2/Diagnostic/CheatSystem.cs index a8ded75f..53398a37 100644 --- a/Assets/Scripts/OpenTS2/Diagnostic/CheatSystem.cs +++ b/Assets/Scripts/OpenTS2/Diagnostic/CheatSystem.cs @@ -1,4 +1,5 @@ -using System; +using Assets.Scripts.OpenTS2.Diagnostic; +using System; using System.Collections.Generic; using System.Linq; using System.Reflection; @@ -18,8 +19,13 @@ public static void Initialize() RegisterCheat(); RegisterCheat(); RegisterCheat(); - RegisterCheat(); + RegisterCheat(); + RegisterCheat(); + RegisterCheat(); Assemblies.AssemblyHelper.AssemblyProcesses += RegisterPropsForType; + + //ConstrainFloorElevation + RegisterProperty(SimpleProperty.Create(false), "constrainfloorelevation"); } private static void RegisterPropsForType(Type type, Assembly assembly) @@ -28,7 +34,7 @@ private static void RegisterPropsForType(Type type, Assembly assembly) var props = type.GetProperties(BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public); foreach (var field in fields) { - var attr = field.GetCustomAttribute(); + var attr = field.GetCustomAttribute(); if (attr != null) { var name = attr.Name; @@ -40,7 +46,7 @@ private static void RegisterPropsForType(Type type, Assembly assembly) } foreach (var prop in fields) { - var attr = prop.GetCustomAttribute(); + var attr = prop.GetCustomAttribute(); if (attr != null) { var name = attr.Name; diff --git a/Assets/Scripts/OpenTS2/Diagnostic/DebugTerrainEditor.cs b/Assets/Scripts/OpenTS2/Diagnostic/DebugTerrainEditor.cs index 740cc737..50432fa5 100644 --- a/Assets/Scripts/OpenTS2/Diagnostic/DebugTerrainEditor.cs +++ b/Assets/Scripts/OpenTS2/Diagnostic/DebugTerrainEditor.cs @@ -64,7 +64,7 @@ private void FixedUpdate() meshFilter.sharedMesh.RecalculateNormals(); if (!UpdateColliderRealtime) collider.sharedMesh = meshFilter.sharedMesh; - var terrainAsset = NeighborhoodManager.CurrentNeighborhood.Terrain; + var terrainAsset = NeighborhoodManager.Instance.CurrentNeighborhood.Terrain; terrainAsset.FromMesh(meshFilter.sharedMesh); terrainAsset.Compressed = true; terrainAsset.Save(); diff --git a/Assets/Scripts/OpenTS2/Diagnostic/EnterCASCheat.cs b/Assets/Scripts/OpenTS2/Diagnostic/EnterCASCheat.cs new file mode 100644 index 00000000..335e9c14 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Diagnostic/EnterCASCheat.cs @@ -0,0 +1,20 @@ +using OpenTS2.Content; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OpenTS2.Diagnostic +{ + public class EnterCASCheat : Cheat + { + public override string Name => "enterCAS"; + public override string Description => "Transitions to CAS."; + + public override void Execute(CheatArguments arguments, IConsoleOutput output = null) + { + CASManager.Instance.EnterCAS(); + } + } +} diff --git a/Assets/Scripts/OpenTS2/Diagnostic/EnterCASCheat.cs.meta b/Assets/Scripts/OpenTS2/Diagnostic/EnterCASCheat.cs.meta new file mode 100644 index 00000000..0f6fc96d --- /dev/null +++ b/Assets/Scripts/OpenTS2/Diagnostic/EnterCASCheat.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 18c7b5a4e1e2d7b45a81352aa842d4b0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Diagnostic/GoToShellCheat.cs b/Assets/Scripts/OpenTS2/Diagnostic/GoToShellCheat.cs index 36ccb14c..13a6e78d 100644 --- a/Assets/Scripts/OpenTS2/Diagnostic/GoToShellCheat.cs +++ b/Assets/Scripts/OpenTS2/Diagnostic/GoToShellCheat.cs @@ -14,7 +14,7 @@ public class GoToShellCheat : Cheat public override void Execute(CheatArguments arguments, IConsoleOutput output = null) { - NeighborhoodManager.LeaveNeighborhood(); + NeighborhoodManager.Instance.LeaveNeighborhood(); } } } diff --git a/Assets/Scripts/OpenTS2/Diagnostic/PauseMusicCheat.cs b/Assets/Scripts/OpenTS2/Diagnostic/PauseMusicCheat.cs new file mode 100644 index 00000000..b469e3cc --- /dev/null +++ b/Assets/Scripts/OpenTS2/Diagnostic/PauseMusicCheat.cs @@ -0,0 +1,27 @@ +using OpenTS2.Audio; +using OpenTS2.Content; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OpenTS2.Diagnostic +{ + public class PauseMusicCheat : Cheat + { + public override string Name => "pauseMusic"; + public override string Description => "Pauses(true) or unpauses(false) the music."; + + public override void Execute(CheatArguments arguments, IConsoleOutput output = null) + { + var musicController = MusicController.Instance; + if (musicController == null) return; + if (arguments.Count < 2) return; + if (arguments.GetBool(1)) + musicController.Pause(); + else + musicController.Resume(); + } + } +} diff --git a/Assets/Scripts/OpenTS2/Diagnostic/PauseMusicCheat.cs.meta b/Assets/Scripts/OpenTS2/Diagnostic/PauseMusicCheat.cs.meta new file mode 100644 index 00000000..89e35868 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Diagnostic/PauseMusicCheat.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d9478f159c7224449999b2ad7bc9e19f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Diagnostic/PlayMusicCategoryCheat.cs b/Assets/Scripts/OpenTS2/Diagnostic/PlayMusicCategoryCheat.cs new file mode 100644 index 00000000..1cb53475 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Diagnostic/PlayMusicCategoryCheat.cs @@ -0,0 +1,24 @@ +using OpenTS2.Audio; +using OpenTS2.Content; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OpenTS2.Diagnostic +{ + public class PlayMusicCategoryCheat : Cheat + { + public override string Name => "playMusicCategory"; + public override string Description => "Makes the MusicController play a specific MusicCategory."; + + public override void Execute(CheatArguments arguments, IConsoleOutput output = null) + { + var musicController = MusicController.Instance; + if (musicController == null) return; + if (arguments.Count < 2) return; + musicController.StartMusicCategory(arguments.GetString(1)); + } + } +} diff --git a/Assets/Scripts/OpenTS2/Diagnostic/PlayMusicCategoryCheat.cs.meta b/Assets/Scripts/OpenTS2/Diagnostic/PlayMusicCategoryCheat.cs.meta new file mode 100644 index 00000000..4c0c7a2e --- /dev/null +++ b/Assets/Scripts/OpenTS2/Diagnostic/PlayMusicCategoryCheat.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5680b8cfb1f91e2419bc69bce3f8ce1a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Engine/AssetController.cs b/Assets/Scripts/OpenTS2/Engine/AssetController.cs index 2b844823..756cb5e4 100644 --- a/Assets/Scripts/OpenTS2/Engine/AssetController.cs +++ b/Assets/Scripts/OpenTS2/Engine/AssetController.cs @@ -12,20 +12,13 @@ namespace OpenTS2.Engine /// public class AssetController : MonoBehaviour { - public static AssetController Singleton => s_singleton; - public static Font DefaultFont => s_singleton._defaultFont; - static AssetController s_singleton = null; + public static AssetController Instance { get; private set; } + public static Font DefaultFont => Instance._defaultFont; [SerializeField] private Font _defaultFont; private void Awake() { - if (s_singleton != null) - { - Destroy(gameObject); - return; - } - s_singleton = this; - DontDestroyOnLoad(gameObject); + Instance = this; } } } diff --git a/Assets/Scripts/OpenTS2/Engine/Core.cs b/Assets/Scripts/OpenTS2/Engine/Core.cs new file mode 100644 index 00000000..5f78e38e --- /dev/null +++ b/Assets/Scripts/OpenTS2/Engine/Core.cs @@ -0,0 +1,68 @@ +using OpenTS2.Assemblies; +using OpenTS2.Content; +using OpenTS2.Diagnostic; +using OpenTS2.Files.Formats.DBPF; +using OpenTS2.Files; +using OpenTS2.Lua; +using OpenTS2.Rendering; +using OpenTS2.SimAntics.Primitives; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; +using UnityEngine.SceneManagement; +using OpenTS2.Game; +using OpenTS2.Audio; +using OpenTS2.Content.DBPF; + +namespace OpenTS2.Engine +{ + public class Core : MonoBehaviour + { + public string TargetScene; + public static Action OnBeginLoading; + public static Action OnFinishedLoading; + public static Action OnNeighborhoodEntered; + public static Action OnLotLoaded; + public static bool CoreInitialized = false; + + public static void InitializeCore() + { + if (CoreInitialized) return; + + var gameGlobals = new GameGlobals(); + var epManager = new EPManager(); + var contentManager = new ContentManager(); + var effectsManager = new EffectsManager(); + var catalogManager = new CatalogManager(); + var luaManager = new LuaManager(); + var musicManager = new MusicManager(); + var audioManager = new AudioManager(); + var nhoodManager = new NeighborhoodManager(); + var casController = new CASManager(); + var lotManger = new LotManager(); + + TerrainManager.Initialize(); + MaterialManager.Initialize(); + Filesystem.InitializeFromJSON("config.json"); + CodecAttribute.Initialize(); + CheatSystem.Initialize(); + VMPrimitiveRegistry.Initialize(); + //Initialize the game assembly, do all reflection things. + AssemblyHelper.InitializeLoadedAssemblies(); + PluginSupport.Initialize(); + + CoreInitialized = true; + } + + private void Awake() + { + InitializeCore(); + DontDestroyOnLoad(gameObject); + if (!string.IsNullOrEmpty(TargetScene)) + SceneManager.LoadScene(TargetScene); + } + } +} diff --git a/Assets/Scripts/OpenTS2/Engine/Core.cs.meta b/Assets/Scripts/OpenTS2/Engine/Core.cs.meta new file mode 100644 index 00000000..969ff560 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Engine/Core.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ad304d4d34fd4274e943ffc0fc2d0436 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: -95 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Diagnostic/ConsolePropertyAttribute.cs b/Assets/Scripts/OpenTS2/Engine/GamePropertyAttribute.cs similarity index 53% rename from Assets/Scripts/OpenTS2/Diagnostic/ConsolePropertyAttribute.cs rename to Assets/Scripts/OpenTS2/Engine/GamePropertyAttribute.cs index 32473130..8d742713 100644 --- a/Assets/Scripts/OpenTS2/Diagnostic/ConsolePropertyAttribute.cs +++ b/Assets/Scripts/OpenTS2/Engine/GamePropertyAttribute.cs @@ -5,19 +5,26 @@ using System.Text; using System.Threading.Tasks; -namespace OpenTS2.Diagnostic +namespace OpenTS2.Engine { /// /// On static variables, allows editing via the cheat console (F3) using the boolprop/intprop/uintprop/stringprop/floatprop cheats. /// [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = false)] - public class ConsolePropertyAttribute : Attribute + public class GamePropertyAttribute : Attribute { - public string Name => _name; - private readonly string _name = ""; - public ConsolePropertyAttribute(string name) + public string Name { get; private set; } + public bool User { get; private set; } + + public GamePropertyAttribute(bool userProp = false) + { + User = userProp; + } + + public GamePropertyAttribute(string name, bool userProp = false) { - _name = name; + Name = name; + User = userProp; } } } diff --git a/Assets/Scripts/OpenTS2/Diagnostic/ConsolePropertyAttribute.cs.meta b/Assets/Scripts/OpenTS2/Engine/GamePropertyAttribute.cs.meta similarity index 100% rename from Assets/Scripts/OpenTS2/Diagnostic/ConsolePropertyAttribute.cs.meta rename to Assets/Scripts/OpenTS2/Engine/GamePropertyAttribute.cs.meta diff --git a/Assets/Scripts/OpenTS2/Engine/JSONPathProvider.cs b/Assets/Scripts/OpenTS2/Engine/JSONPathProvider.cs deleted file mode 100644 index ac364c26..00000000 --- a/Assets/Scripts/OpenTS2/Engine/JSONPathProvider.cs +++ /dev/null @@ -1,59 +0,0 @@ -/* - * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. - * If a copy of the MPL was not distributed with this file, You can obtain one at - * http://mozilla.org/MPL/2.0/. - */ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using OpenTS2.Content.Interfaces; -using UnityEngine; -using System.IO; -using OpenTS2.Content; - -namespace OpenTS2.Engine -{ - [Serializable] - public class JSONConfig - { - public string game_dir; - public string user_dir; - public List dlc; - } - - /// - /// Provides game paths from a config.json file. - /// - public class JSONPathProvider : IPathProvider - { - readonly JSONConfig _config; - public JSONPathProvider() - { - var dir = new DirectoryInfo(Application.dataPath).Parent.FullName; - _config = JsonUtility.FromJson(File.ReadAllText(Path.Combine(dir, "config.json"))); - } - public string GetPathForProduct(ProductFlags productFlag) - { - var index = Array.IndexOf(Enum.GetValues(productFlag.GetType()), productFlag); - return Path.Combine(_config.game_dir, _config.dlc[index]); - } - - public string GetDataPathForProduct(ProductFlags productFlag) - { - return GetPathForProduct(productFlag) + "/TSData"; - } - - public string GetBinPathForProduct(ProductFlags productFlag) - { - return GetPathForProduct(productFlag) + "/TSBin"; - } - - public string GetUserPath() - { - return _config.user_dir; - } - } -} diff --git a/Assets/Scripts/OpenTS2/Engine/Main.cs b/Assets/Scripts/OpenTS2/Engine/Main.cs deleted file mode 100644 index d735c281..00000000 --- a/Assets/Scripts/OpenTS2/Engine/Main.cs +++ /dev/null @@ -1,47 +0,0 @@ -using OpenTS2.Assemblies; -using OpenTS2.Client; -using OpenTS2.Content; -using OpenTS2.Diagnostic; -using OpenTS2.Files; -using OpenTS2.Files.Formats.DBPF; -using OpenTS2.Rendering; -using OpenTS2.SimAntics.Primitives; -using OpenTS2.Lua; -using UnityEngine; - -namespace OpenTS2.Engine -{ - /// - /// Main initialization class for Unity Engine implementation of OpenTS2. - /// - public static class Main - { - static bool s_initialized = false; - /// - /// Initializes all singletons, systems and the game assembly. - /// - [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] - public static void Initialize() - { - if (s_initialized) - return; - var settings = new Settings(); - var epManager = new EPManager(); - var contentProvider = new ContentProvider(); - var objectManager = new ObjectManager(contentProvider); - var effectsManager = new EffectsManager(contentProvider); - var catalogManager = new CatalogManager(contentProvider); - var luaManager = new LuaManager(); - - TerrainManager.Initialize(); - MaterialManager.Initialize(); - Filesystem.Initialize(new JSONPathProvider(), epManager); - CodecAttribute.Initialize(); - CheatSystem.Initialize(); - VMPrimitiveRegistry.Initialize(); - //Initialize the game assembly, do all reflection things. - AssemblyHelper.InitializeLoadedAssemblies(); - s_initialized = true; - } - } -} diff --git a/Assets/Scripts/OpenTS2/Engine/MemoryController.cs b/Assets/Scripts/OpenTS2/Engine/MemoryController.cs index b55e1660..7595c0c4 100644 --- a/Assets/Scripts/OpenTS2/Engine/MemoryController.cs +++ b/Assets/Scripts/OpenTS2/Engine/MemoryController.cs @@ -13,22 +13,8 @@ namespace OpenTS2.Engine /// public class MemoryController : MonoBehaviour { - public static MemoryController Singleton => s_singleton; - static MemoryController s_singleton = null; - private static Action MarkedForRemoval; - private void Awake() - { - if (s_singleton != null) - { - Destroy(gameObject); - return; - } - s_singleton = this; - DontDestroyOnLoad(gameObject); - } - public static void MarkForRemoval(Action action) { lock (MarkedForRemoval) diff --git a/Assets/Scripts/OpenTS2/Engine/Modes.meta b/Assets/Scripts/OpenTS2/Engine/Modes.meta new file mode 100644 index 00000000..819c8022 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Engine/Modes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1df3d8a68fd8f874eb366660526b7c53 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Engine/Modes/Build.meta b/Assets/Scripts/OpenTS2/Engine/Modes/Build.meta new file mode 100644 index 00000000..378aafd1 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Engine/Modes/Build.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 28f9123fa5bd6d04ea188898ff9c5c80 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Engine/Modes/Build/BuildModeServer.cs b/Assets/Scripts/OpenTS2/Engine/Modes/Build/BuildModeServer.cs new file mode 100644 index 00000000..25d7ff18 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Engine/Modes/Build/BuildModeServer.cs @@ -0,0 +1,664 @@ +using OpenTS2.Content.DBPF; +using OpenTS2.Engine.Modes.Build.Tools; +using OpenTS2.Scenes.Lot; +using UnityEngine; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using OpenTS2.Scenes.Lot.Extensions; +using OpenTS2.Scenes.Lot.State; +using log4net.Core; +using UnityEngine.UIElements; +using OpenTS2.Files.Formats.DBPF; +using OpenTS2.Diagnostic; + +namespace OpenTS2.Engine.Modes.Build +{ + + /// + /// Controls the flow of changes to the lot architecture and serves the functionality for Build Mode + /// + internal class BuildModeServer : MonoBehaviour + { + /// + /// Modes that walls can be created + /// + public enum WallCreationModes + { + /// + /// A single normal wall + /// + Single, + /// + /// A square area of walls + /// + Room, + /// + /// A diagonally oriented square area of walls + /// + DiagnonalRoom + } + /// + /// Modes that describe the modification being made to the terrain + /// + public enum TerrainModificationModes + { + /// + /// No brush selected + /// + None, + /// + /// Raise the terrain brush + /// + Raise, + /// + /// Lower the terrain brush + /// + Lower, + /// + /// Smooth an area of terrain brush + /// + Smooth, + /// + /// Pond brush + /// + Water, + /// + /// Terrain paints brush + /// + Paint + } + + //STATIC + private static BuildModeServer Current { get; set; } + public static BuildModeServer Get() => Current; + + private static Dictionary _tools; + private ushort dryWallDesignPattern; + /// + /// The floor currently selected using the UI + /// This also is the highest level shown in the lot geometry + /// + public int CurrentFloor => loadedLot.Floor; + + //PRIVATE + private readonly StringBuilder lotHistory = new StringBuilder(); + + private readonly LotLoad loadedLot; + private LotArchitecture architecture => loadedLot.Architecture; + private bool ConstrainedFloorElevation => CheatSystem.GetProperty("constrainfloorelevation").GetStringValue().ToLower() == "true"; + + //PUBLIC + /// + /// The current + /// See: + /// + public WorldState WorldState + { + get => loadedLot.WorldState; set => loadedLot.WorldState = value; + } + /// + /// After making changes to the , use this to apply the changes + /// + public void InvalidateLotState() => loadedLot.InvalidateState(); + /// + /// The tool that the user is currently using (or the one the user more recently selected) + /// + public BuildTools SelectedTool { get; private set;} = BuildTools.None; + /// + /// The handler for the tool the user is currently using + /// + public AbstractBuildTool CurrentTool { get; private set; } = null; + public int BaseFloor => loadedLot.BaseFloor; + public int MaxFloor => loadedLot.MaxFloor; + + private void LogHistory(string Message, string Caption = default, string Sender = default) + { + if (string.IsNullOrWhiteSpace(Sender)) Sender = typeof(BuildModeServer).Name; + var msgTxt = $"OpenTS2::{Sender} -> {(!string.IsNullOrWhiteSpace(Caption) ? $"({Caption})" : "")} {Message}"; + lotHistory.AppendLine(msgTxt); + Debug.Log(msgTxt); + } + + internal BuildModeServer(LotLoad LoadedLot) + { + Current = this; + + loadedLot = LoadedLot; + + SelectedTool = BuildTools.None; + CurrentTool = null; + + MakeTools(); + Init(); + } + + void MakeTools() + { + _tools = new Dictionary + { // funfact: these are added in the order they were implemented .. incase you were wondering + { BuildTools.Wall, new WallTool(this) }, + { BuildTools.Hand, new HandTool(loadedLot, architecture) }, + { BuildTools.TerrainBrush, new TerrainBrushTool(this) }, + { BuildTools.Floor, new FloorTool(this) }, + { BuildTools.Foundation, new FoundationTool(this) } + }; + } + + void Init() + { + //set drywall design pattern (used so frequently we can save a little time frontloading it) + architecture.EnsurePatternReferenced("blank", LotArchitecture.ArchitectureGameObjectTypes.wall, out dryWallDesignPattern, out _); + } + /// + /// Changes the currently used tool by the User. + /// Passing will drop the current tool, if held. + /// + /// + public void ChangeTool(BuildTools Tool) + { + if (CurrentTool != null) + { // A tool is currently being used. + if (Tool == SelectedTool) + return; // the newly selected tool is the same as the one currently held, exit. + CurrentTool.OnToolCancel(Tool != BuildTools.None ? "The user selected a different tool." : "The current tool has been dropped."); + CurrentTool.SetActive(false); + } + switch(Tool) + { + default: + case BuildTools.None: + CurrentTool = null; break; + case BuildTools.Foundation: + case BuildTools.Hand: + case BuildTools.Wall: + case BuildTools.TerrainBrush: + case BuildTools.Floor: + CurrentTool = _tools[Tool]; + CurrentTool.SetActive(true); + LogHistory($"Selected tool: {Tool} (trans from: {SelectedTool})", "Change Tool"); + break; + } + SelectedTool = Tool; + } + + /// + /// Lists all the points for wall segments in the area of walls provided + /// + /// + /// + /// + /// + public static List<(Vector2Int A, Vector2Int B)> GetWallPoints(Vector2Int From, Vector2Int To, WallCreationModes CreationOption = WallCreationModes.Single) + { + List<(Vector2Int A, Vector2Int B)> walls = new List<(Vector2Int, Vector2Int)>(); + switch (CreationOption) + { + case WallCreationModes.Single: + walls.Add((From, To)); + break; + case WallCreationModes.Room: + walls.Add((From, new Vector2Int(To.x, From.y))); + walls.Add((new Vector2Int(To.x, From.y), To)); + walls.Add((To, new Vector2Int(From.x, To.y))); + walls.Add((new Vector2Int(From.x, To.y), From)); + break; + case WallCreationModes.DiagnonalRoom: break; + } + return walls; + } + + public float PollElevation(Vector2Int Position, int Floor) => architecture.PollElevation(Position, Floor); + + /// + /// Creates walls with the blank wallpaper set with optional creation options like Square area of walls or Single + /// + /// + /// + /// + /// + /// + public int[]? CreateWalls(Vector2Int From, Vector2Int To, int Floor, + WallType Type = WallType.Normal, + WallCreationModes CreationOption = WallCreationModes.Single, + string FrontWallpaperPattern = "blank", string BackWallpaperPattern = "blank") + { + if (From == To) return null; + if (CreationOption != WallCreationModes.Single && !RegionValid(From, To)) return null; + string argsStr = $"From: {From} To: {To} Floor: {Floor} Type: {Type} Mode: {CreationOption}" + + $"Front: {FrontWallpaperPattern} Back: {BackWallpaperPattern}"; + + //OrderPoints(ref From, ref To); + var walls = GetWallPoints(From, To, CreationOption); + + //WALLPAPERS + ushort front = dryWallDesignPattern; + ushort back = front; + if (FrontWallpaperPattern != "blank") + architecture.EnsurePatternReferenced(FrontWallpaperPattern, LotArchitecture.ArchitectureGameObjectTypes.wall, out front, out _); + if (BackWallpaperPattern != "blank") + architecture.EnsurePatternReferenced(BackWallpaperPattern, LotArchitecture.ArchitectureGameObjectTypes.wall, out back, out _); + + int[] createdWallIDs = null; + foreach (var wall in walls) + createdWallIDs = architecture.CreateWall(wall.A, wall.B, Floor, Type, front, back); + + if (createdWallIDs != null) // walls were placed here + { + loadedLot.InvalidateWalls(); + LogHistory($"Created wall(s). {argsStr}", "Create Walls"); + return createdWallIDs; + } + else LogHistory($"Could not create wall(s). {argsStr}", "Create Walls"); + return null; + } + /// + /// Causes the room detection system to re-evaluate the lot. + /// + public void SignalRoomsInvalidate() => loadedLot.EvaluateRoomMap(); + /// + /// Clears out all walls in the specified region with the given wall creation options + /// + /// + /// + /// + /// + /// + public void DeleteWalls(Vector2Int From, Vector2Int To, int Floor, WallCreationModes CreationOption = WallCreationModes.Single) + { + var walls = GetWallPoints(From, To, CreationOption); + string argsStr = $"From: {From} To: {To} Floor: {Floor} Mode: {CreationOption}"; + + bool? returnValue = true; + foreach (var wall in walls) + returnValue = architecture.DeleteWall(wall.A, wall.B, Floor); + + if (returnValue.HasValue) // walls were placed here + { + loadedLot.InvalidateWalls(); + LogHistory($"Deleted wall(s). {argsStr}", "Delete Walls"); + } + else LogHistory($"Could not delete wall(s). {argsStr}", "Delete Walls"); + } + public void DeleteAllWalls(params int[] WallLayerIDs) + { + if (WallLayerIDs.Length == 0) return; + architecture.DeleteAllWalls(WallLayerIDs); + loadedLot.InvalidateWalls(); + } + + /// + /// Puts the two points in ascending order + /// + void OrderPoints(ref Vector2Int A, ref Vector2Int B) + { + var a = new Vector2Int(Math.Min(A.x, B.x), Math.Min(A.y, B.y)); + var b = new Vector2Int(Math.Max(A.x, B.x), Math.Max(A.y, B.y)); + A = a; + B = b; + } + + /// + /// Checks if the area between two points is nonzero + /// + /// + /// + /// + bool RegionValid(Vector2Int From, Vector2Int To) => Math.Abs(From.x - To.x) * Math.Abs(From.y - To.y) != 0; + + /// + /// Checks to see if there is a floor at the given location. + /// If is provided as , it will check floors on ALL levels. + /// + /// + /// + /// + public bool IsFloorAt(Vector2Int Position, int? Level = default) + { + bool inquire(int level, int index) + { + var value = architecture.FloorPatterns.Data[level][index]; + return value.w != 0 || value.x != 0 || value.y != 0 || value.z != 0; + } + + int level = 0; + bool allLevels = Level == default; + if (!allLevels) + level = -architecture.BaseFloor + Level.Value; + + var mPos = Position; + + bool inquiryList(int level, int index) + { + if (inquire(level, index)) return true; + if (index == 0) return false; + if (inquire(level, index - 1)) return true; + index = ((mPos.x - 1) * architecture.FloorPatterns.Height) + mPos.y; + if (inquire(level, index)) return true; + return false; + } + + int index = (mPos.x * architecture.FloorPatterns.Height) + mPos.y; + + if (!allLevels) + return inquiryList(level, index); + + for (level = architecture.BaseFloor; level < architecture.FloorPatterns.Data.Length; level++) + if (inquiryList(level, index)) return true; + return false; + } + + /// + /// Ensures the provided has layers up to the provided floor level + /// + /// Function used to fill the array's new level(s) if applicable. + /// arg1 is the index in the array being filled + /// arg2 is the value at arg1 on the floor beneath this one. If this is the lowest floor, + /// it will reference itself. + void Ensure3DViewDepth2Floor(_3DArrayView ArrayView, int Floor, Func FillFunc) where T : unmanaged + { + //ensure a layer for elevation exists + if (ArrayView.Depth <= Floor) + { + int fromFloor = ArrayView.Depth; + int toFloor = Floor; + //make new level(s) + ArrayView.Resize(Floor + 1); + for(int f = fromFloor; f <= toFloor; f++) + { // iterate over new level(s) + int underFloor = f - 1; + if (underFloor < BaseFloor) underFloor = BaseFloor; + for (int i = 0; i < ArrayView.Width * ArrayView.Height; i++) + { + T underValue = ArrayView.Data[underFloor][i]; + ArrayView.Data[f][i] = FillFunc(i, underValue); // invoke fillfunc to fill the array + } + } + ArrayView.Commit(); + } + } + /// + /// Ensures the provided has layers up to the provided floor level + /// + /// Value used to fill the newly created array levels + void Ensure3DViewDepth2Floor(_3DArrayView ArrayView, int Floor, T DefaultFillVal) where T : unmanaged + { + //ensure a layer for elevation exists + if (ArrayView.Depth <= Floor) + { + int fromFloor = ArrayView.Depth; + int toFloor = Floor; + //make new level(s) + ArrayView.Resize(Floor + 1); + for (int f = fromFloor; f <= toFloor; f++) + { // iterate over new level(s) + for (int i = 0; i < ArrayView.Width * ArrayView.Height; i++) + ArrayView.Data[f][i] = DefaultFillVal; // invoke fillfunc to fill the array + } + ArrayView.Commit(); + } + } + + public void DeleteFloors(Vector2Int From, Vector2Int To, int Level = 0) => + CreateFloors(From, To, 0, Level, false); + /// + /// Creates an area of flooring with the specified . + /// This function handles adding the pattern reference to the + /// + /// + /// + /// + /// + /// + public void CreateFloors(Vector2Int From, Vector2Int To, string PatternName, int Level = 0, bool ModifyTerrain = true) + { + if (!architecture.EnsurePatternReferenced(PatternName, LotArchitecture.ArchitectureGameObjectTypes.floor, out ushort patternID, out _)) + { + LogHistory($"Could not create flooring due to the pattern: {PatternName} not existing or isn't valid."); + return; + } + CreateFloors(From, To, patternID, Level, ModifyTerrain); + } + public void CreateFloors(Vector2Int From, Vector2Int To, ushort PatternID, int Level = 0, bool ModifyTerrain = true) => + CreateFloors(From, To, new Files.Formats.DBPF.Vector4(PatternID, PatternID, PatternID, PatternID), Level, ModifyTerrain); + public void CreateFloors(Vector2Int From, Vector2Int To, + Vector4 QuarterTilePatternIDs, int Level = 0, bool ModifyTerrain = true) + { + if (!RegionValid(From, To)) return; // check area nonzero + + var from = From; var to = To; // order the points in order of closest to origin of the lot first + OrderPoints(ref from, ref to); + + if (ModifyTerrain) // flatten the area of terrain if applicable + { + Vector2Int pollPosition = From; // NE corner of the origin tile always + if(From.y > To.y) // selection is towards NORTH + pollPosition.y -= 1; + else pollPosition.y += 1; + if (From.x > To.x) // selection is towards WEST + ; + else pollPosition.x += 1; + + float elevation = architecture.PollElevation(pollPosition, Level); + LevelRegion(from, to, elevation, Level); // level terrain under floors + } + Level = -architecture.BaseFloor + Level; + _3DArrayView> floorPatterns = architecture.FloorPatterns; + + //ensure a layer for elevation exists + Ensure3DViewDepth2Floor(floorPatterns, Level, new Vector4()); // fill with empty + + ref Vector4[] baseFloorData = ref floorPatterns.Data[Level]; + + int changedFloors = 0; + for (int tx = from.x; tx < to.x; tx++) + { + for (int ty = from.y; ty < to.y; ty++) + { + var mPos = new Vector2Int(tx, ty); + int index = (mPos.x * floorPatterns.Height) + mPos.y; + + if (index > baseFloorData.Length - 1) + index = baseFloorData.Length - 1; + if (index < 0) + index = 0; + + baseFloorData[index] = QuarterTilePatternIDs; + changedFloors++; + } + } + + if (changedFloors <= 0) return; + + LogHistory($"Modified flooring. From: {From} To: {To} PatIDs: {QuarterTilePatternIDs}" + + $" Floor: {Level} TerrainMod?: {ModifyTerrain}", "Modify Flooring"); + loadedLot.InvalidateFloors(); // invalidating floors also may incur a terrain re-evaluation if necessary + } + + /// + /// Levels a region of terrain/elevation map. + /// + /// The point to start at + /// The point to go to. + /// What elevation value to level to. + /// Which level of the Elevation Map to perform the modification. + /// If true, will ensure each level beneath does not exceed this elevation. + /// Only greater elevations will be modified, lower ones will be ignored. + /// In the event the terrain on a lower floor exceeds the elevation here on this floor, by how much to + /// decrease to yield the elevation of the terrain on the lower floor? + public void LevelRegion(Vector2Int From, Vector2Int To, float Elevation = 0, int Floor = 0, bool LevelFloorsBeneathMe = true, float LevelBeneathMeDelta = -0f) + { + if (!RegionValid(From, To)) return; + Floor = -architecture.BaseFloor + Floor; + + var from = From; var to = To; + OrderPoints(ref from, ref to); + + //check the cheat system for constrainfloorelevation cheat + bool cfeProp = ConstrainedFloorElevation; + + _3DArrayView arr = architecture.Elevation; + + //ensure a layer for elevation exists + //fill function will set the entire level to appropriate wall height. + Ensure3DViewDepth2Floor(arr, Floor, (int i, float beneathElevation) => beneathElevation + LotWallComponent.WallHeight); + + ref float[] dataSet = ref arr.Data[Floor]; + bool levelModify = false; + for (int tx = from.x; tx <= to.x; tx++) + { + for(int ty = from.y; ty <= to.y; ty++) + { + var mPos = new Vector2Int(tx, ty); + int index = (mPos.x * arr.Height) + mPos.y; + + if (index > dataSet.Length - 1) + index = dataSet.Length - 1; + if (index < 0) + index = 0; + + if (cfeProp && IsFloorAt(mPos)) + continue; + + dataSet[index] = Elevation; + levelModify = true; + + //level beneath me + if (LevelFloorsBeneathMe) + { + try + { + for (int elevationLevel = Floor; elevationLevel > 0; elevationLevel--) + { + ref float[] meValDataSet = ref arr.Data[elevationLevel - 1]; + meValDataSet[index] = Math.Min(Elevation + LevelBeneathMeDelta, meValDataSet[index]); + } + } + catch (Exception e) + { + Debug.LogError($"LevelRegion() :: LevelBeneathMe error: {e.Message}"); + } + } + } + } + + if (!levelModify) return; + + LogHistory($"Leveled terrain. From: {From} To: {To} Elevation: {Elevation}" + + $" Floor: {Floor}", "Level Terrain"); + //all changes complete, invalidate mesh + loadedLot.InvalidateFloors(); + } + /// + /// Sets the elevation at the position in lot grid coordinates at the Floor provided by adding it to the elevation of the lower level. + /// + /// + /// + /// + public void SetElevationRelative(float RelativeElevation, int Floor, params Vector2Int[] Positions) + { + Floor = -architecture.BaseFloor + Floor; + + _3DArrayView arr = architecture.Elevation; + //ensure a layer for elevation exists + //fill function will set the entire level to appropriate wall height. + Ensure3DViewDepth2Floor(arr, Floor, (int i, float beneathElevation) => beneathElevation + RelativeElevation); + + ref float[] dataSet = ref arr.Data[Floor]; + foreach (var p in Positions) + { + var mPos = p; + int index = (mPos.x * arr.Height) + mPos.y; + + float lowerElevation = dataSet[index]; + if (Floor > 0) + lowerElevation = arr.Data[Floor - 1][index]; + + dataSet[index] = lowerElevation + RelativeElevation; + } + } + + /// + /// Submits a terrain modification with the supplied parameters + /// + /// The center point of the terrain modification, in lot grid coordinates + /// The radius of the terrain brush being used, in grid cells + /// By how much should the terrain be altered in this call + /// Which modification is requested + /// + public bool ModifyTerrain(Vector2Int Position, int Radius, float Strength, TerrainModificationModes Mode, int Floor = 0) + { + if (Mode == TerrainModificationModes.None) return false; + Floor = -architecture.BaseFloor + Floor; + ref float[] dataSet = ref architecture.Elevation.Data[Floor]; + + var mPos = Position; + int index = (mPos.x * architecture.Elevation.Height) + mPos.y; + + //The Sims 2 won't allow any terrain modifications if the cursor is directly over unexposed terrain + if (ConstrainedFloorElevation && IsFloorAt(mPos, Floor)) + return false; + + bool levelModify = false; + + for (int dx = -Radius; dx <= Radius; dx++) + { + for (int dy = -Radius; dy <= Radius; dy++) + { + //get position to edit + mPos = Position + new Vector2Int(dx, dy); + index = (mPos.x * architecture.Elevation.Height) + mPos.y; + + //measure length from center to this point + int length = (int)Math.Round(Vector2.Distance(mPos, Position),0); + if (length > Radius) continue; + + float _stren = Strength; + + //CFE cheat + if (ConstrainedFloorElevation && IsFloorAt(mPos)) + continue; + + //terrain modification + switch (Mode) + { + default: return false; // ?? + case TerrainModificationModes.Water: + case TerrainModificationModes.Lower: + _stren *= -1; + goto case TerrainModificationModes.Raise; + case TerrainModificationModes.Raise: + dataSet[index] += _stren; + levelModify = true; + break; + } + } + } + + if (!levelModify) return false; + + LogHistory($"{Mode}ed terrain. Center: {Position} Radius: {Radius} Strength: {Strength} Level: {Floor}", "Level Terrain"); + //all changes complete, invalidate mesh + loadedLot.InvalidateFloors(); + return true; + } + + /// + /// Resets the lot to having nothing on it and flattened terrain + /// Note: It is highly recommended to alert the user before performing an action like this. + /// + /// + public void FlattenLot(float Elevation = 0) + { + int Floor = 0; + Floor = -architecture.BaseFloor + Floor; + ref float[] dataSet = ref architecture.Elevation.Data[-architecture.BaseFloor]; + for(int i = 0; i < dataSet.Length; i++) + dataSet[i] = Elevation; + //all changes complete, invalidate mesh + loadedLot.InvalidateFloors(); + } + } +} diff --git a/Assets/Scripts/OpenTS2/Engine/Modes/Build/BuildModeServer.cs.meta b/Assets/Scripts/OpenTS2/Engine/Modes/Build/BuildModeServer.cs.meta new file mode 100644 index 00000000..e776a78d --- /dev/null +++ b/Assets/Scripts/OpenTS2/Engine/Modes/Build/BuildModeServer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1e91cfd046356bd4496e1fe219b072b9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Engine/Modes/Build/BuildTools.cs b/Assets/Scripts/OpenTS2/Engine/Modes/Build/BuildTools.cs new file mode 100644 index 00000000..626c10ae --- /dev/null +++ b/Assets/Scripts/OpenTS2/Engine/Modes/Build/BuildTools.cs @@ -0,0 +1,12 @@ +namespace OpenTS2.Engine.Modes.Build +{ + internal enum BuildTools + { + None, + Hand, + Wall, + TerrainBrush, + Foundation, + Floor, + } +} diff --git a/Assets/Scripts/OpenTS2/Engine/Modes/Build/BuildTools.cs.meta b/Assets/Scripts/OpenTS2/Engine/Modes/Build/BuildTools.cs.meta new file mode 100644 index 00000000..979e247e --- /dev/null +++ b/Assets/Scripts/OpenTS2/Engine/Modes/Build/BuildTools.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: be91059a50da924489cf226bdd5d6d45 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools.meta b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools.meta new file mode 100644 index 00000000..502e3bdb --- /dev/null +++ b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4b7ab705d82e6f8419b9d1db9e8ff271 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/AbstractBuildTool.cs b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/AbstractBuildTool.cs new file mode 100644 index 00000000..878da93a --- /dev/null +++ b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/AbstractBuildTool.cs @@ -0,0 +1,296 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace OpenTS2.Engine.Modes.Build.Tools +{ + /// + /// Context passed a parameter for functions on a instance + /// + internal class BuildToolContext + { + /// + /// The position of the 3D mouse cursor in world space + /// + public Vector3 Cursor3DWorldPosition { get; set; } + /// + /// The position of the wand snapped to grid coordinates + /// + public Vector3 WandPosition { get; set; } + /// + /// The position of the wand in the 2D lot grid + /// + public Vector2Int GridPosition { get; set; } + /// + /// The quadrant the 3D mouse cursor is in + /// Chart Quadrants: 1 = top left, 2 = top right, 3 = bottom right, 4 = bottom left + /// + public int GridTileCursorQuadrant { get; set; } + public int CursorFloor { get; internal set; } + } + + /// + /// A build tool with basic Pick-Up and Put-Down functionality + /// + internal abstract class AbstractBuildTool + { + public delegate void OnFinalizeToolHandler(AbstractBuildTool sender); + /// + /// Called when the user releases the tool and the changes will be submitted. + /// + public event OnFinalizeToolHandler OnFinalizeTool; + + /// + /// The name of this tool + /// + public abstract string ToolName { get; } + /// + /// The current type of tool this instance is acting as + /// + public abstract BuildTools ToolType { get; } + /// + /// True when the tool is actively being used by the user. (A wall is being created, for instance) + /// + public bool IsHolding { get; protected set; } + /// + /// True when the tool is not being actively used but is ready for user input + /// + public bool IsActive { get; private set; } = false; + /// + /// The position within the lot boundaries of the tool at the current time + /// + public Vector3 ToolLotPosition { get; protected set; } + /// + /// The position on the grid that the tool is currently nearest to + /// + public Vector2 ToolGridPosition { get; protected set; } + /// + /// Sets the property + /// + /// + public void SetActive(bool Activated) + { + IsActive = Activated; + OnActiveChanged(Activated); + } + protected abstract void OnActiveChanged(bool NewValue); + /// + /// Called once per frame for the tool to process changes between frames + /// + /// + public virtual void OnToolUpdate(BuildToolContext Context) + { + ToolLotPosition = Context.WandPosition; + ToolGridPosition = Context.GridPosition; + } + /// + /// Called when a tool begins to be used by the user + /// + /// + public abstract void OnToolStart(BuildToolContext Context); + /// + /// Called when a tool is cancelled. + /// Note: Calling this at any time will immediately cancel the current tool action, you can give a reason to add clarity + /// to why this was called. + /// + /// + public abstract void OnToolCancel(string Reason = null); + /// + /// Called when the user commits to an action. (Left click) + /// + /// + public virtual void OnToolFinalize(BuildToolContext Context) => OnFinalizeTool?.Invoke(this); + } + + /// + /// Represents shared behavior for tools in Build Mode where the user can click and drag an area to manipulate the lot + /// + internal abstract class AbstractRegionSelectBuildTool : AbstractBuildTool + { + //protected fields + /// + /// Defines behaviors for how the cursor should react to moving between levels + /// + protected enum MultilevelBehavior + { + /// + /// If the cursor leaves the level it started dragging, cancel the action immediately. + /// + CancelAction, + /// + /// If the cursor is not at the same level as it started when the action is finished, cancel the action. + /// Unlike , the action won't be cancelled immediately. + /// + Deny, + /// + /// Allows the cursor to freely move between levels and will not intervene. + /// + Allow, + /// + /// Keeps the level the same as when the tool started dragging so the level is retained even when the cursor moves between levels + /// + Constrain, + } + + protected Vector2Int toolDragStart; + protected Vector2Int toolDragEnd; + protected Vector2Int toolLastActionDragEnd; + protected Vector3 toolDragStartWorldPos; + protected int toolDragFloor; + + //public properties + /// + /// Where the user drag gesture initiated, in lot grid coordinates + /// + public Vector2Int ToolDragOrigin => toolDragStart; + /// + /// Where the user drag gesture ended, in lot grid coordinates + /// + public Vector2Int ToolDragDestination => toolDragEnd; + /// + /// Where the user drag gesture started in terms of which floor + /// + public int ToolDragFloor => toolDragFloor; + + //Protected + protected bool DeleteMode { get; set; } + protected static GameObject ToolCursorObject { get; set; } + protected static Transform ToolCursorObjectTransform => ToolCursorObject.transform; + protected static GameObject SelectionStartToolCursor { get; set; } + /// + /// See: + /// + protected virtual MultilevelBehavior MultiLevelBehavior { get; set; } = MultilevelBehavior.Deny; + + protected BuildModeServer BuildModeServer { get; } + + protected AbstractRegionSelectBuildTool(BuildModeServer Server) : base() + { + BuildModeServer = Server; + Init(); + } + + protected virtual void Init() + { + //get the default Wand + if (ToolCursorObject == null) + ToolCursorObject = GameObject.Find("Wand"); + if (SelectionStartToolCursor == null) + { + SelectionStartToolCursor = GameObject.Find("debugWandCompanion"); + SelectionStartToolCursor.SetActive(false); + } + } + + protected override void OnActiveChanged(bool NewValue) + { + ToolCursorObject.SetActive(NewValue); + if (!NewValue) SelectionStartToolCursor.SetActive(false); + } + + public override void OnToolStart(BuildToolContext Context) + { + if (IsHolding) return; // huh? weird edge case here + IsHolding = true; + toolDragStart = toolDragEnd = toolLastActionDragEnd = Context.GridPosition; + toolDragFloor = Context.CursorFloor; + + //set the selection origin cursor + toolDragStartWorldPos = Context.WandPosition; + SelectionStartToolCursor.SetActive(true); + SelectionStartToolCursor.transform.position = Context.WandPosition; + return; + } + + public override void OnToolUpdate(BuildToolContext Context) + { + base.OnToolUpdate(Context); + + var dirtyToolDragEnd = toolDragEnd; + + if (!IsActive) return; + ToolCursorObjectTransform.position = Context.WandPosition; + if (!IsHolding) return; + toolDragEnd = Context.GridPosition; + + if (MultiLevelBehavior == MultilevelBehavior.CancelAction && toolDragFloor != Context.CursorFloor) + {// drag between floors! + OnToolCancel("Start and end positions are not at the same level."); + return; + } + + //check if player change wall creation type + CheckDeleteMode(); + + if(dirtyToolDragEnd != toolDragEnd) + //clear any created wall facades + DoHoverAction(true); + toolLastActionDragEnd = toolDragEnd; + + //User let go of the Wand, signal finalize event + if (!Input.GetMouseButton(0)) + { // finalize + OnToolFinalize(Context); + return; + } + + if (dirtyToolDragEnd != toolDragEnd) + //Update facade + DoHoverAction(); + } + + public override void OnToolFinalize(BuildToolContext Context) + { + IsHolding = false; // finish drag gesture + if (toolDragStart == toolDragEnd) return; // misclick + if ((MultiLevelBehavior == MultilevelBehavior.CancelAction || MultiLevelBehavior == MultilevelBehavior.Deny) + && toolDragFloor != Context.CursorFloor) + {// drag between floors! + OnToolCancel("Start and end positions are not at the same level."); + return; + } + + //check if player change creation type + CheckDeleteMode(); + //Create / Delete the area + DoAction(); + + SelectionStartToolCursor.SetActive(false); // hide cursor + IsHolding = false; // drop tool + + base.OnToolFinalize(Context); + } + + public override void OnToolCancel(string Reason) + { + DoHoverAction(true); + + SelectionStartToolCursor.SetActive(false); // hide cursor + IsHolding = false; // drop tool + + Debug.Log($"{ToolName} cancelled. Reason: {Reason ?? "none given"}"); + } + + protected virtual void CheckDeleteMode() + { + //check if deleting objects + DeleteMode = false; + if (Input.GetKey(KeyCode.LeftControl)) DeleteMode = true; + } + /// + /// Performs the action that this tool advertises. + /// Note: This is not the same thing as as that is distinctly + /// when the user finishes the action. can be called many times depending on the implementation. + /// + /// + protected abstract void DoAction(bool Undo = false); + /// + /// Same as except with the intention of previewing the action before committing it + /// + /// + protected virtual void DoHoverAction(bool Undo = false) => DoAction(Undo); + } +} diff --git a/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/AbstractBuildTool.cs.meta b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/AbstractBuildTool.cs.meta new file mode 100644 index 00000000..6d4038e1 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/AbstractBuildTool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: be2df28f574842c48b230b4c3cf403dc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/FloorTool.cs b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/FloorTool.cs new file mode 100644 index 00000000..6a8a745a --- /dev/null +++ b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/FloorTool.cs @@ -0,0 +1,83 @@ +namespace OpenTS2.Engine.Modes.Build.Tools +{ + /// + /// Build tools that allow the user to make selections using the catalog in Build Mode + /// + internal interface ICatalogSelectableBuildTool + { + + } + /// + /// Build tool that takes patterns from Build Mode (walls and floors) + /// + internal interface IPatternSelectableBuildTool + { + /// + /// Dictates whether the tool should be using the or property + /// + bool IDPainting { get; } + + /// + /// The name of the pattern's material + /// + string PatternName { get; } + /// + /// The ID of the pattern in the target component map. + /// Walls and Floors (for example) both have individual WallMaps and FloorMaps + /// independent of one another and this mode should generally not be used in favor of . + /// + ushort PatternID { get; } + + /// + /// Sets the pattern the floor tool is currently painting + /// + void SetPaintPattern(string PatternName); + /// + /// Sets the pattern the floor tool is currently painting + /// + void SetPaintPatternID(ushort PatternID); + } + + /// + /// This Build Tool allows the User to drag out areas of flooring. + /// It invokes the for all lot modifications + /// + internal class FloorTool : AbstractRegionSelectBuildTool, IPatternSelectableBuildTool + { + public override string ToolName => "Floor Tool"; + public override BuildTools ToolType => BuildTools.Floor; + public bool IDPainting { get; private set; } + public string PatternName { get; private set; } + public ushort PatternID { get; private set; } + + public FloorTool(BuildModeServer Server) : base(Server) { } + + public void SetPaintPattern(string PatternName) + { + IDPainting = false; + this.PatternName = PatternName; + } + public void SetPaintPatternID(ushort PatternID) + { + IDPainting = true; + this.PatternID = PatternID; + } + + protected override void DoAction(bool Undo = false) + { + if (DeleteMode) + BuildModeServer.DeleteFloors(ToolDragOrigin, ToolDragDestination, ToolDragFloor); + else + { + if (IDPainting) + BuildModeServer.CreateFloors(ToolDragOrigin, ToolDragDestination, PatternID, ToolDragFloor); + else BuildModeServer.CreateFloors(ToolDragOrigin, ToolDragDestination, PatternName, ToolDragFloor); + } + } + + protected override void DoHoverAction(bool Undo = false) + { + ; + } + } +} diff --git a/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/FloorTool.cs.meta b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/FloorTool.cs.meta new file mode 100644 index 00000000..50429916 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/FloorTool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: af9a2f90db10abc4390cbda8afdecf9b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/FoundationTool.cs b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/FoundationTool.cs new file mode 100644 index 00000000..6f714be4 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/FoundationTool.cs @@ -0,0 +1,92 @@ +using OpenTS2.Content.DBPF; +using OpenTS2.Engine.Modes.Build.Tools; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace OpenTS2.Engine.Modes.Build.Tools +{ + /// + /// A build tool for creating foundations on the lot + /// This tool can be boiled down to the and put together + /// + internal class FoundationTool : AbstractRegionSelectBuildTool + { + const float FoundationHeight = 1; + const string FoundationWallpaper = "foundationbrick"; + private const string FoundationFlooring = "wood_wide_planks"; + + /// + /// Sets up a new Foundation Tool with the specified walls and floors + /// By default this is The Sims 2 default values Brick walls and Wood floors + /// + /// + /// + /// + public FoundationTool(BuildModeServer Server, + string Wallpaper = FoundationWallpaper, + string Flooring = FoundationFlooring) : base(Server) + { + WallpaperPattern = Wallpaper; + FlooringPattern = Flooring; + } + + public override string ToolName => "Foundation Tool"; + public override BuildTools ToolType => BuildTools.Foundation; + + //**PATTERN + /// + /// The pattern to paint the walls when creating a Foundation + /// + public string WallpaperPattern { get; set; } + /// + /// The pattern to paint the floors when creating a Foundation + /// + public string FlooringPattern { get; set; } + //*** + + protected override MultilevelBehavior MultiLevelBehavior { get; set; } = MultilevelBehavior.Constrain; + + + protected override void DoAction(bool Undo = false) + { + if (DeleteMode) Undo = !Undo; + if (ToolDragFloor > 1) + { + OnToolCancel("Foundation can only be placed on terrain."); + return; + } + + int currFloor = 0; + int nextFloor = currFloor + 1; + + float elevation = BuildModeServer.PollElevation(ToolDragOrigin, ToolDragFloor); + if (ToolDragFloor == 0) + elevation += FoundationHeight; + //This levels the Elevation map where the floor is on this foundation. + //This makes the walls stubby and the floor appear seamless. This also uses the LevelBeneathMe feature of the function. + //It will ensure all terrain beneath the foundation is less than the elevation -.1f. + BuildModeServer.LevelRegion(ToolDragOrigin, ToolDragDestination, elevation, nextFloor, true, -.1f); + if (!Undo) + { + BuildModeServer.CreateWalls(ToolDragOrigin, ToolDragDestination, currFloor, + Content.DBPF.WallType.Foundation, BuildModeServer.WallCreationModes.Room, + WallpaperPattern, WallpaperPattern); + BuildModeServer.CreateFloors(ToolDragOrigin, ToolDragDestination, FlooringPattern, nextFloor, false); + } + else + { + BuildModeServer.DeleteWalls(ToolDragOrigin, ToolDragDestination, currFloor, BuildModeServer.WallCreationModes.Room); + BuildModeServer.DeleteFloors(ToolDragOrigin, ToolDragDestination, nextFloor); + } + } + + protected override void DoHoverAction(bool Undo = false) + { + ; + } + } +} diff --git a/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/FoundationTool.cs.meta b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/FoundationTool.cs.meta new file mode 100644 index 00000000..b73ebff2 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/FoundationTool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 62528670419620547b98daca6a7118d5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/HandTool.cs b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/HandTool.cs new file mode 100644 index 00000000..f2123bd2 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/HandTool.cs @@ -0,0 +1,102 @@ +using OpenTS2.Components; +using OpenTS2.Scenes.Lot; +using System.Linq; +using UnityEngine; + +namespace OpenTS2.Engine.Modes.Build.Tools +{ + //*** NEEDS A REWORK ONCE SCENEGRAPH RENDERING IS REWORKED BECAUSE THIS IS NOT A GOOD SOLUTION + internal class HandTool : AbstractBuildTool + { + private LotLoad loadedLot; + private LotArchitecture architecture; + + private Transform holdingObjectRoot; + private GameObject holdingObjectReference; + private Vector3 originalPosition; + bool IsHoldingObject => holdingObjectReference != null; + + public override string ToolName => "Hand Tool"; + public override BuildTools ToolType => BuildTools.Hand; + + /// + /// Creates a new on the specified lot + /// + /// + /// + public HandTool(LotLoad loadedLot, LotArchitecture architecture) + { + this.loadedLot = loadedLot; + this.architecture = architecture; + + Init(); + } + + private void Init() + { + + } + + public override void OnToolCancel(string Reason) + { + if (!IsHoldingObject) return; + + holdingObjectRoot.position = originalPosition; + + holdingObjectReference = null; + holdingObjectRoot = null; + + Debug.Log($"{ToolName} cancelled. Reason: {Reason ?? "null"}"); + } + + public override void OnToolUpdate(BuildToolContext Context) + { + base.OnToolUpdate(Context); + + if (!IsHoldingObject) return; + holdingObjectRoot.position = Context.WandPosition; + + if (Input.GetMouseButtonDown(0)) + OnToolFinalize(Context); + } + + public override void OnToolFinalize(BuildToolContext Context) + { + if (!IsHoldingObject) return; + + holdingObjectRoot.position = Context.WandPosition; + + holdingObjectReference = null; + holdingObjectRoot = null; + + base.OnToolFinalize(Context); + } + + public override void OnToolStart(BuildToolContext Context) + { + // PERFORM OBJECT HITTEST (The colliders are added in ScenegraphComponent) + Ray camRay = TestLotViewCamera.GetMouseCursor3DRay(Camera.main); + var hits = Physics.RaycastAll(camRay); + + if (hits.Any()) + { // find any hits + foreach (RaycastHit hit in hits.OrderBy(x => x.distance)) + { + var parent = hit.collider.gameObject.transform.parent.gameObject; + if (parent.GetComponent() != null) + { + holdingObjectReference = parent; + holdingObjectRoot = holdingObjectReference.transform; + originalPosition = holdingObjectRoot.position; + break; + } + } + } + } + + protected override void OnActiveChanged(bool NewValue) + { + + } + } +} diff --git a/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/HandTool.cs.meta b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/HandTool.cs.meta new file mode 100644 index 00000000..07a9c5d6 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/HandTool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4bac8d546ec25bb4e94cf635b9d3d75f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/TerrainBrushTool.cs b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/TerrainBrushTool.cs new file mode 100644 index 00000000..78882de4 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/TerrainBrushTool.cs @@ -0,0 +1,109 @@ +using UnityEngine; +using static OpenTS2.Engine.Modes.Build.BuildModeServer; + +namespace OpenTS2.Engine.Modes.Build.Tools +{ + /// + /// Handles the functionality for the Wall Tool interacting with the lot + /// + internal class TerrainBrushTool : AbstractBuildTool + { + /// + /// Radii of terrain brush sizes + /// + public enum TerrainBrushSizes + { + Small = 0, // since this tool is only 1 point, it's not a tile wide + Medium = 2, + Large = 4 + } + + //private + BuildModeServer buildModeServer; + ushort dryWallDesignPattern; + private GameObject rootWallCursor; + private Transform _wallCursorTransform; + + /// + /// The current brush mode the tool is using + /// + public BuildModeServer.TerrainModificationModes CurrentBrushMode { get; set; } + /// + /// The current stroke thickness of the brush + /// + public int BrushSize { get; set; } = (int)TerrainBrushSizes.Large; + public float BrushStrength { get; set; } = 1f; + + /// + /// Creates a new on the specified lot + /// + /// + /// + public TerrainBrushTool(BuildModeServer Server) + { + buildModeServer = Server; + Init(); + } + + void Init() + { + //get the default Wand + rootWallCursor = GameObject.Find("Wand"); + _wallCursorTransform = rootWallCursor.transform; + } + + public override string ToolName => "Terrain Tool"; + public override BuildTools ToolType => BuildTools.TerrainBrush; + + protected override void OnActiveChanged(bool NewValue) + { + rootWallCursor.SetActive(NewValue); + CurrentBrushMode = TerrainModificationModes.Raise; + } + + public override void OnToolCancel(string Reason) + { + IsHolding = false; // drop tool + + Debug.Log($"{ToolName} cancelled. Reason: {Reason ?? "null"}"); + } + + public override void OnToolFinalize(BuildToolContext Context) + { + IsHolding = false; // finish brush stroke + + base.OnToolFinalize(Context); + } + + public override void OnToolStart(BuildToolContext Context) + { + if (IsHolding) return; // huh? weird edge case here + IsHolding = true; // brush stroke start + + CommitToolStroke(Context.GridPosition); // makes single clicks (only lasting a frame) possible + } + + public override void OnToolUpdate(BuildToolContext Context) + { + base.OnToolUpdate(Context); + + if (!IsActive) return; + _wallCursorTransform.position = Context.WandPosition; + if (!IsHolding) return; + + //User let go of the Wand, signal finalize event + if (!Input.GetMouseButton(0)) + { // finalize + OnToolFinalize(Context); + return; + } + //user is still painting + CommitToolStroke(Context.GridPosition); + } + + void CommitToolStroke(Vector2Int position) + { + buildModeServer.ModifyTerrain(position, BrushSize, BrushStrength * Time.deltaTime, CurrentBrushMode); + } + } +} diff --git a/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/TerrainBrushTool.cs.meta b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/TerrainBrushTool.cs.meta new file mode 100644 index 00000000..de132f71 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/TerrainBrushTool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 322a39bbf1f7a8446b4b6194c8ec1abf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/WallTool.cs b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/WallTool.cs new file mode 100644 index 00000000..b2721ce3 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/WallTool.cs @@ -0,0 +1,124 @@ +using OpenTS2.Content.DBPF; +using OpenTS2.Engine.Modes.Build.Tools; +using OpenTS2.Scenes.Lot; +using OpenTS2.Scenes.Lot.Extensions; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; +using static OpenTS2.Engine.Modes.Build.BuildModeServer; + +namespace OpenTS2.Engine.Modes.Build.Tools +{ + /// + /// Handles the functionality for the Wall Tool interacting with the lot + /// + internal class WallTool : AbstractRegionSelectBuildTool + { + // Wall cursor tool + WallCreationModes wallCreateMode = WallCreationModes.Single; + bool deletingWalls => DeleteMode; + + //private + /// + /// This is used when dragging an area of walls. + /// The walls created as a facade have their IDs stored here. + /// When the action is cancelled or the facade changes, these IDs + /// will be used to delete the unneeded walls. + /// + HashSet facadeWallIDs = new HashSet(); + BuildModeServer buildModeServer => BuildModeServer; + bool Hovering = false; + + /// + /// Creates a new on the specified lot + /// + /// + /// + public WallTool(BuildModeServer Server) : base(Server) { } + + public override string ToolName => "Wall Tool"; + public override BuildTools ToolType => BuildTools.Wall; + + /// + /// Updates depending on the player's current input + /// + protected override void CheckDeleteMode() + { + //creation mode + WallCreationModes mode = WallCreationModes.Single; + if (Input.GetKey(KeyCode.LeftShift)) mode = WallCreationModes.Room; + wallCreateMode = mode; + + //check delete mode + base.CheckDeleteMode(); + } + + /// + /// Creates/Deletes the walls in the selected space + /// + protected override void DoAction(bool Undoing = false) + { + bool actionSelected = !deletingWalls; + Vector2Int destination = toolDragEnd; + if (deletingWalls) destination = toolLastActionDragEnd; + if (Undoing) + { + if(destination != toolLastActionDragEnd) + destination = toolLastActionDragEnd; + else destination = toolDragEnd; + actionSelected = !actionSelected; + } + if (toolDragStart - destination == new Vector2Int(0, 0)) + { + if (Hovering && facadeWallIDs.Count > 0) + { + buildModeServer.DeleteAllWalls(facadeWallIDs.ToArray()); + facadeWallIDs.Clear(); + } + return; // zero area + } + if (actionSelected) + { + float startElevation = buildModeServer.PollElevation(toolDragStart, toolDragFloor); + //level upper elevation to ensure the wall is the correct size + foreach (var segment in GetWallPoints(toolDragStart, destination, wallCreateMode)) + { + //level terrain beneath the wall + //buildModeServer.SetElevationRelative(startElevation, toolDragFloor, segment.A, segment.B); + //level above the wall to ensure the height is accurate + buildModeServer.SetElevationRelative(LotWallComponent.WallHeight, toolDragFloor + 1, segment.A, segment.B); + } + var createdWallIDs = buildModeServer.CreateWalls(toolDragStart, destination, toolDragFloor, WallType.Normal, wallCreateMode); + if (Hovering) + { + if (createdWallIDs != null) + Array.ForEach(createdWallIDs, (int item) => facadeWallIDs.Add(item)); + } + else if (facadeWallIDs.Any()) + { + facadeWallIDs.Clear(); + buildModeServer.SignalRoomsInvalidate(); + } + } + else + { + if (Hovering && facadeWallIDs.Count > 0) + { + buildModeServer.DeleteAllWalls(facadeWallIDs.ToArray()); + facadeWallIDs.Clear(); + } + buildModeServer.DeleteWalls(toolDragStart, destination, ToolDragFloor, wallCreateMode); + } + } + + protected override void DoHoverAction(bool Undo = false) + { + Hovering = true; + DoAction(Undo); + Hovering = false; + } + } +} diff --git a/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/WallTool.cs.meta b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/WallTool.cs.meta new file mode 100644 index 00000000..e49f6257 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/WallTool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7ed8cbcbc0bb3d24f864d9ff7650d4e6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Engine/Tests/AsyncTest.cs b/Assets/Scripts/OpenTS2/Engine/Tests/AsyncTest.cs index 57f36a17..958b4fe2 100644 --- a/Assets/Scripts/OpenTS2/Engine/Tests/AsyncTest.cs +++ b/Assets/Scripts/OpenTS2/Engine/Tests/AsyncTest.cs @@ -32,8 +32,8 @@ void Start() { ContentLoading.LoadContentStartup(); PluginSupport.Initialize(); - MusicSource.clip = AudioManager.SplashAudio.Clip; - MusicSource.Play(); + //MusicSource.clip = MusicManager.SplashAudio.Clip; + //MusicSource.Play(); stopW = new Stopwatch(); stopW.Start(); if (async) @@ -52,24 +52,13 @@ void Update() void OnFinishLoading() { - var contentProvider = ContentProvider.Get(); - var oMgr = ObjectManager.Get(); - oMgr.Initialize(); + var contentManager = ContentManager.Instance; stopW.Stop(); UnityEngine.Debug.Log("Done loading packages!"); - UnityEngine.Debug.Log(contentProvider.ContentEntries.Count + " packages loaded."); + UnityEngine.Debug.Log(contentManager.ContentEntries.Count + " packages loaded."); UnityEngine.Debug.Log("Package loading took " + (stopW.ElapsedTicks * 1000000 / Stopwatch.Frequency) + " microseconds"); - var objectStr = "Object Amount: " + oMgr.Objects.Count + System.Environment.NewLine; - for(var i=0;i<200;i++) - { - if (i >= oMgr.Objects.Count) - break; - var element = oMgr.Objects[(oMgr.Objects.Count-1)-i]; - objectStr += element.FileName + " (" + "0x"+element.GUID.ToString("X8") + ")" + System.Environment.NewLine; - } - ObjectsText.text = objectStr; - PopupBackgroundImage.texture = contentProvider.GetAsset(new ResourceKey(0xA9600400, 0x499DB772, 0x856DDBAC)).Texture; - BackgroundImage.texture = contentProvider.GetAsset(new ResourceKey(0xCCC9AF70, 0x499DB772, 0x856DDBAC)).Texture; + PopupBackgroundImage.texture = contentManager.GetAsset(new ResourceKey(0xA9600400, 0x499DB772, 0x856DDBAC)).Texture; + BackgroundImage.texture = contentManager.GetAsset(new ResourceKey(0xCCC9AF70, 0x499DB772, 0x856DDBAC)).Texture; } } } \ No newline at end of file diff --git a/Assets/Scripts/OpenTS2/Engine/Tests/BuildModeTest.cs b/Assets/Scripts/OpenTS2/Engine/Tests/BuildModeTest.cs new file mode 100644 index 00000000..7a6885f7 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Engine/Tests/BuildModeTest.cs @@ -0,0 +1,144 @@ +// JDrocks450 11-22-2023 on GitHub + +using OpenTS2.Common; +using OpenTS2.Content; +using OpenTS2.Content.DBPF.Scenegraph; +using OpenTS2.Content.DBPF; +using OpenTS2.Files.Formats.DBPF; +using OpenTS2.Files; +using OpenTS2.Scenes.Lot.State; +using OpenTS2.Scenes.Lot; +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using UnityEngine; +using static OpenTS2.Content.DBPF.LotObjectAsset; +using OpenTS2.Scenes.Lot.Extensions; +using OpenTS2.Engine.Modes.Build; +using OpenTS2.UI.Layouts; +using OpenTS2.Client; +using System.Linq; +using OpenTS2.UI.Layouts.Lot; +using UnityEditor.SearchService; +using OpenTS2.Engine.Modes.Build.Tools; + +/// +/// Serves the behavior for the Build Mode Test scene +/// +public class BuildModeTest : MonoBehaviour +{ + // Init + LotLoad _loadedLotProvider; + LotArchitecture _architectrue => _loadedLotProvider.Architecture; + TestLotViewCamera viewCamera; + BuildModeServer buildServer; + LotViewHUDController hudController; + + void ContentStartup(bool LoadGameContent = true) + { + EPManager.Get().InstalledProducts = 0x3EFFF; + ContentLoading.LoadContentStartup(); + + var settings = Settings.Get(); + settings.CustomContentEnabled = false; + + if (!LoadGameContent) return; + + // Load effects. + EffectsManager.Get().Initialize(); + //load the game content + ContentLoading.LoadGameContentSync(); + + CatalogManager.Get().Initialize(); + } + + void Awake() + { + //Load content + ContentStartup(true); + } + + void Start() + { + //load the default lot for now + _loadedLotProvider = new LotLoad("N001", 80); + + //create the build mode server + buildServer = new BuildModeServer(_loadedLotProvider); + buildServer.ChangeTool(BuildTools.None); + + //set the camera transform + viewCamera = GameObject.Find("Main Camera").GetComponent(); + + //connect to the HUD controller + hudController = GameObject.Find("Scene/LotViewUIController").GetComponent(); + hudController.Puck.SetMode(LotViewHUD.HUD_UILotModes.Build); // set puck display state to be Build mode + hudController.Puck.OnModeChangeRequested += HUD_GameModeRequest; + } + + private void HUD_GameModeRequest(object sender, LotViewHUD.ModeChangeEventArgs e) + { + e.Allow = false; // locked in Build Mode for the time being + } + + // Update is called once per frame + void Update() + { + HandleTool(); + } + + void HandleTool() + { + if (buildServer.CurrentTool == null) return; + + //set cursor position + ReevaluateTerrainMesh(); + bool successful = viewCamera.TranslateScreen2WorldPos(_loadedLotProvider.Floor, out var terrainPosition, out int currentCursorFloor); + if (!successful) return; // do not update the cursor when the mouse leaves the lot boundary. this prevents any events from firing with build tools + var buildCursorPos = new Vector3((float)Math.Round(terrainPosition.x, 0), terrainPosition.y, (float)Math.Round(terrainPosition.z, 0)); + Vector2Int wallcurPos = new Vector2Int((int)buildCursorPos.x, (int)buildCursorPos.z); // flat grid position for wall tool + + //context + BuildToolContext context = new BuildToolContext() + { + Cursor3DWorldPosition = terrainPosition, + WandPosition = buildCursorPos, + GridPosition = wallcurPos, + CursorFloor = currentCursorFloor + }; + + buildServer.CurrentTool.OnToolUpdate(context); // mouse moved + if (Input.GetMouseButtonDown(0)) // mouse left click start + { // start drag + buildServer.CurrentTool.OnToolStart(context); + return; + } + if (Input.GetKeyDown(KeyCode.Escape)) + { + buildServer.CurrentTool.OnToolCancel("User cancelled using the ESC key."); + return; + } + } + + /// + /// Resets the -- this may be necessary when the terrain mesh is updated, for example + /// + void ReevaluateTerrainMesh() + { + var floorComp = _architectrue.GetComponentByType(LotArchitecture.ArchitectureGameObjectTypes.floor); + for(int floor = 0; floor < _architectrue.BaseFloor + _architectrue.Elevation.Depth; floor++) + { + int actualFloor = _architectrue.BaseFloor + floor; + List collidersByFloor = new List(); + if (actualFloor == 0) + { + var terrainObject = GameObject.Find("terrain/Terrain"); + collidersByFloor.Add(terrainObject.GetComponent()); + } + if(floorComp.TryGetCollidersByFloor(floor, out var colliders)) + collidersByFloor.AddRange(colliders); + viewCamera.SetCameraDetectionMeshes(actualFloor, collidersByFloor); + } + } +} diff --git a/Assets/Scripts/OpenTS2/Engine/Tests/BuildModeTest.cs.meta b/Assets/Scripts/OpenTS2/Engine/Tests/BuildModeTest.cs.meta new file mode 100644 index 00000000..96a90ea0 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Engine/Tests/BuildModeTest.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 94cb5833fa52cfc4392f5daf80bc17b3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Engine/Tests/EffectsTest.cs b/Assets/Scripts/OpenTS2/Engine/Tests/EffectsTest.cs index 2dfba3ff..2d5f60d7 100644 --- a/Assets/Scripts/OpenTS2/Engine/Tests/EffectsTest.cs +++ b/Assets/Scripts/OpenTS2/Engine/Tests/EffectsTest.cs @@ -8,17 +8,17 @@ public class EffectsTest : MonoBehaviour { private void Start() { - var contentProvider = ContentProvider.Get(); + var contentManager = ContentManager.Instance; // Load base game assets. - contentProvider.AddPackages( - Filesystem.GetPackagesInDirectory(Filesystem.GetDataPathForProduct(ProductFlags.BaseGame) + "/Res/Sims3D")); + contentManager.AddPackages( + Filesystem.GetPackagesInDirectory(Filesystem.GetPathForProduct(ProductFlags.BaseGame) + "TSData/Res/Sims3D")); // Initialize effects manager manually since we aren't using startup controller. - EffectsManager.Get().Initialize(); + EffectsManager.Instance.Initialize(); //var effect = EffectsManager.Get().CreateEffectWithUnityTransform("neighborhood_house_smoking"); - var effect = EffectsManager.Get().CreateEffectWithUnityTransform("neighborhood_hanggliders"); + var effect = EffectsManager.Instance.CreateEffectWithUnityTransform("neighborhood_hanggliders"); //var effect = EffectsManager.Get().CreateEffectWithUnityTransform("neighborhood_hotairballoon"); effect.PlayEffect(); diff --git a/Assets/Scripts/OpenTS2/Engine/Tests/LotImposterGMDCTest.cs b/Assets/Scripts/OpenTS2/Engine/Tests/LotImposterGMDCTest.cs index 679d33ce..4e7aff23 100644 --- a/Assets/Scripts/OpenTS2/Engine/Tests/LotImposterGMDCTest.cs +++ b/Assets/Scripts/OpenTS2/Engine/Tests/LotImposterGMDCTest.cs @@ -16,13 +16,13 @@ public class LotImposterGMDCTest : MonoBehaviour public int LotID = 11; private void Start() { - var contentProvider = ContentProvider.Get(); - var lotsFolderPath = Path.Combine(Filesystem.GetUserPath(), $"Neighborhoods/{NeighborhoodPrefix}/Lots"); + var contentManager = ContentManager.Instance; + var lotsFolderPath = Path.Combine(Filesystem.UserDataDirectory, $"Neighborhoods/{NeighborhoodPrefix}/Lots"); var lotFilename = $"{NeighborhoodPrefix}_Lot{LotID}.package"; var lotFullPath = Path.Combine(lotsFolderPath, lotFilename); - contentProvider.AddPackage(lotFullPath); + contentManager.AddPackage(lotFullPath); - var lotImposterResource = contentProvider.GetAssetsOfType(TypeIDs.SCENEGRAPH_CRES)[0]; + var lotImposterResource = contentManager.GetAssetsOfType(TypeIDs.SCENEGRAPH_CRES)[0]; var gameObject = lotImposterResource.CreateRootGameObject(); } diff --git a/Assets/Scripts/OpenTS2/Engine/Tests/LotLoadingTest.cs b/Assets/Scripts/OpenTS2/Engine/Tests/LotLoadingTest.cs index b93756a6..78c9fe5b 100644 --- a/Assets/Scripts/OpenTS2/Engine/Tests/LotLoadingTest.cs +++ b/Assets/Scripts/OpenTS2/Engine/Tests/LotLoadingTest.cs @@ -10,7 +10,6 @@ using OpenTS2.Files.Formats.DBPF; using OpenTS2.Scenes.Lot; using OpenTS2.Scenes.Lot.State; -using UnityEditor; using UnityEngine; namespace OpenTS2.Engine.Tests @@ -48,12 +47,14 @@ private void UnloadLot() private void Start() { + Core.InitializeCore(); + // Load effects. - EffectsManager.Get().Initialize(); + EffectsManager.Instance.Initialize(); ContentLoading.LoadGameContentSync(); - CatalogManager.Get().Initialize(); + CatalogManager.Instance.Initialize(); LoadLot(NeighborhoodPrefix, LotID); } @@ -119,9 +120,9 @@ private void LoadLot(string neighborhoodPrefix, int id) _nhood = neighborhoodPrefix; _lotId = id; - var contentProvider = ContentProvider.Get(); + var contentManager = ContentManager.Instance; - var lotsFolderPath = Path.Combine(Filesystem.GetUserPath(), $"Neighborhoods/{NeighborhoodPrefix}/Lots"); + var lotsFolderPath = Path.Combine(Filesystem.UserDataDirectory, $"Neighborhoods/{NeighborhoodPrefix}/Lots"); var lotFilename = $"{NeighborhoodPrefix}_Lot{LotID}.package"; var lotFullPath = Path.Combine(lotsFolderPath, lotFilename); @@ -130,7 +131,7 @@ private void LoadLot(string neighborhoodPrefix, int id) return; } - var lotPackage = contentProvider.AddPackage(lotFullPath); + var lotPackage = contentManager.AddPackage(lotFullPath); // Go through each lot object. foreach (var entry in lotPackage.Entries) @@ -143,7 +144,7 @@ private void LoadLot(string neighborhoodPrefix, int id) try { var lotObject = entry.GetAsset(); - var resource = contentProvider.GetAsset( + var resource = contentManager.GetAsset( new ResourceKey(lotObject.Object.ResourceName + "_cres", GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_CRES)); if (resource == null) @@ -176,100 +177,4 @@ private void LoadLot(string neighborhoodPrefix, int id) _architecture.UpdateState(_state); } } - - [CustomEditor(typeof(LotLoadingTest))] - public class LotLoadingTestEditor : Editor - { - private string _cachedNhood = ""; - private List NhoodNames = new List() { "N001" }; - private List LotIds = new List() { 82 }; - - public LotLoadingTestEditor() - { - PopulateNhoodList(); - } - - private void PopulateNhoodList() - { - NhoodNames.Clear(); - - var nhoodFolderPath = Path.Combine(Filesystem.GetUserPath(), $"Neighborhoods"); - - foreach (var nhood in Directory.GetDirectories(nhoodFolderPath)) - { - string filename = Path.GetFileName(nhood); - - if (filename.Length == 4) - { - NhoodNames.Add(filename); - } - } - } - - private void PopulateLotList(string nhood) - { - _cachedNhood = nhood; - var lotsFolderPath = Path.Combine(Filesystem.GetUserPath(), $"Neighborhoods/{nhood}/Lots"); - - LotIds.Clear(); - - try - { - foreach (string file in Directory.GetFiles(lotsFolderPath)) - { - if (file.EndsWith(".package")) - { - int tIndex = file.LastIndexOf('t'); - int end = file.Length - ".package".Length; - string lotIdProbably = file.Substring(tIndex + 1, end - (tIndex + 1)); - - if (int.TryParse(lotIdProbably, out int lotId)) - { - LotIds.Add(lotId); - } - } - } - } - catch - { - - } - - LotIds.Sort(); - } - - public override void OnInspectorGUI() - { - var test = target as LotLoadingTest; - - Main.Initialize(); - - string[] noptions = NhoodNames.ToArray(); - int nindex = EditorGUILayout.Popup("Neighborhood", NhoodNames.IndexOf(test.NeighborhoodPrefix), noptions); - if (nindex > -1) - { - test.NeighborhoodPrefix = NhoodNames[nindex]; - } - - if (test.NeighborhoodPrefix != _cachedNhood) - { - PopulateLotList(test.NeighborhoodPrefix); - } - - string[] options = LotIds.Select(x => "Lot " + x.ToString()).ToArray(); - int index = EditorGUILayout.Popup("Lot ID", LotIds.IndexOf(test.LotID), options); - if (index > -1) - { - test.LotID = LotIds[index]; - } - - WallsMode walls = (WallsMode)EditorGUILayout.EnumPopup("Walls", test.Mode); - test.Mode = walls; - - int floor = EditorGUILayout.IntSlider(test.Floor, 1, test.MaxFloor + test.BaseFloor); - test.Floor = floor; - - test.Changed(); - } - } } \ No newline at end of file diff --git a/Assets/Scripts/OpenTS2/Engine/Tests/LotObjectSimulationTest.cs b/Assets/Scripts/OpenTS2/Engine/Tests/LotObjectSimulationTest.cs new file mode 100644 index 00000000..20b49de6 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Engine/Tests/LotObjectSimulationTest.cs @@ -0,0 +1,135 @@ +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using OpenTS2.Common; +using OpenTS2.Content; +using OpenTS2.Content.DBPF; +using OpenTS2.Files; +using OpenTS2.Files.Formats.DBPF; +using OpenTS2.SimAntics; +using UnityEngine; + +namespace OpenTS2.Engine.Tests +{ + /// + /// Tests loading an object from a lot and then running the SimAntics simulator on it. + /// + public class LotObjectSimulationTest : MonoBehaviour + { + public string NeighborhoodPrefix = "N002"; + public int LotID = 22; + // Which item to load from the lot save table. + public int ItemIndex = 0; + + private string _nhood; + private int _lotId; + + void Start() + { + Core.InitializeCore(); + + ContentLoading.LoadGameContentSync(); + + CatalogManager.Instance.Initialize(); + ObjectManager.Create(); + + LoadLot(NeighborhoodPrefix, LotID); + } + + private void LoadLot(string neighborhoodPrefix, int id) + { + _nhood = neighborhoodPrefix; + _lotId = id; + + var contentManager = ContentManager.Instance; + + var lotsFolderPath = Path.Combine(Filesystem.UserDataDirectory, $"Neighborhoods/{NeighborhoodPrefix}/Lots"); + var lotFilename = $"{NeighborhoodPrefix}_Lot{LotID}.package"; + var lotFullPath = Path.Combine(lotsFolderPath, lotFilename); + + if (!File.Exists(lotFullPath)) + { + return; + } + + var lotPackage = contentManager.AddPackage(lotFullPath); + + // Get the version of objects and their IDs from the Edith Object module file OBJM. + var objectModule = + lotPackage.GetAssetByTGI(new ResourceKey(instanceID: 1, groupID: GroupIDs.Local, + TypeIDs.OBJM)); + foreach (var key in objectModule.ObjectIdToSaveType.Keys) + { + Debug.Log($"item id: {key}"); + } + Debug.Log($"ItemIndex: {ItemIndex}"); + var objectToLoadSaveType = objectModule.ObjectIdToSaveType[ItemIndex]; + + // Get the lot's OBJT / object save type table. + var saveTable = + lotPackage.GetAssetByTGI(new ResourceKey(instanceID: 0, GroupIDs.Local, + TypeIDs.OBJ_SAVE_TYPE_TABLE)); + + var saveTypeToGuid = new Dictionary(); + for (var index = 0; index < saveTable.Selectors.Count; index++) + { + var selector = saveTable.Selectors[index]; + var def = ObjectManager.Instance.GetObjectByGUID(selector.objectGuid); + if (def == null) + { + continue; + } + + saveTypeToGuid[selector.saveType] = selector.objectGuid; + //Debug.Log($"{index}: saveType: {selector.saveType} resource name: {selector.catalogResourceName}, Obj name: {def.FileName}"); + } + + Debug.Log($"ItemIndex: {ItemIndex}, saveType: {objectToLoadSaveType}"); + var objectToLoad = saveTable.Selectors[objectToLoadSaveType]; + + var objectDefinition = ObjectManager.Instance.GetObjectByGUID(objectToLoad.objectGuid); + Debug.Assert(objectDefinition != null, "Could not find objd."); + + Debug.Log($"Loading object {objectToLoad.catalogResourceName} with guid {objectToLoad.objectGuid:X} group: {objectDefinition.GlobalTGI.GroupID:X}"); + + // Now load the state of the object. + var objectStateBytes = lotPackage.GetBytesByTGI( + new ResourceKey(instanceID: (uint)ItemIndex, GroupIDs.Local, TypeIDs.XOBJ)); + var objectState = SimsObjectCodec.DeserializeFromBytesAndVersion(objectStateBytes, objectModule.Version); + + // Create an entity for the object. + var vm = new VM(); + var entity = new VMEntity(objectDefinition) + { + Attributes = objectState.Attrs, + SemiAttributes = objectState.SemiAttrs, + Temps = objectState.Temp, + ObjectData = objectState.Data + }; + + foreach (var frame in objectState.StackFrames) + { + Debug.Log("Frame -----"); + Debug.Log($" TreeId: 0x{frame.TreeId:X}, bhavSaveType: {frame.BhavSaveType}"); + + var bhavObjDef = ObjectManager.Instance.GetObjectByGUID(saveTypeToGuid[frame.BhavSaveType]); + // TODO: add a static method to do this or something. We don't want to make a VMEntity instance just + // to get the BHAV. + var bhav = new VMEntity(bhavObjDef).GetBHAV(frame.TreeId); + + var vmFrame = new VMStackFrame(bhav, entity.MainThread) + { + Arguments = frame.Params, + Locals = frame.Locals + }; + entity.MainThread.Frames.Push(vmFrame); + + Debug.Log($" BHAV TGI: {entity.MainThread.Frames.Peek().BHAV.GlobalTGI}"); + Debug.Log($" params: ({string.Join(", ", vmFrame.Arguments)})"); + } + + vm.Tick(); + } + } +} diff --git a/Assets/Scripts/OpenTS2/Engine/Tests/LotObjectSimulationTest.cs.meta b/Assets/Scripts/OpenTS2/Engine/Tests/LotObjectSimulationTest.cs.meta new file mode 100644 index 00000000..2bf49b38 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Engine/Tests/LotObjectSimulationTest.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 54fe40fa056264c4ab3d016b539c0210 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Engine/Tests/LuaTestController.cs b/Assets/Scripts/OpenTS2/Engine/Tests/LuaTestController.cs index 1b6c94b1..5674b2f1 100644 --- a/Assets/Scripts/OpenTS2/Engine/Tests/LuaTestController.cs +++ b/Assets/Scripts/OpenTS2/Engine/Tests/LuaTestController.cs @@ -18,14 +18,14 @@ public class LuaTestController : MonoBehaviour void Start() { // Initialize lua engine, register a test API so that we can use UnityLog and hook GetSimulatorGlobal to return 27 as day of the month, 8 as month and 2023 as year. - var luaManager = LuaManager.Get(); + var luaManager = LuaManager.Instance; luaManager.RegisterAPI(new LuaTestAPI()); luaManager.InitializeObjectScripts(); // nTime is defined in the game's "Time" global Lua script. try { - LuaManager.Get().RunScript(@"local time = nTime.Now() + LuaManager.Instance.RunScript(@"local time = nTime.Now() UnityLog('Lua Year is ' .. time.mYears) UnityLog('Lua Month is ' .. time.mMonths) UnityLog('Lua Day is ' .. time.mDays)"); @@ -40,7 +40,7 @@ void Start() if (DumpLuaScripts) { - var objectScriptsPath = Filesystem.GetLatestFilePath("Res/ObjectScripts/ObjectScripts.package"); + var objectScriptsPath = Filesystem.GetLatestFilePath("TSData/Res/ObjectScripts/ObjectScripts.package"); var objectScriptsFile = new DBPFFile(objectScriptsPath); foreach(var entry in objectScriptsFile.Entries) diff --git a/Assets/Scripts/OpenTS2/Engine/Tests/ReiaTest.cs b/Assets/Scripts/OpenTS2/Engine/Tests/ReiaTest.cs index 123e0eea..b631077f 100644 --- a/Assets/Scripts/OpenTS2/Engine/Tests/ReiaTest.cs +++ b/Assets/Scripts/OpenTS2/Engine/Tests/ReiaTest.cs @@ -29,16 +29,14 @@ public class ReiaTest : MonoBehaviour private void Start() { - var realPath = Filesystem.GetRealPath(reiaPath); - var streamFs = File.OpenRead(realPath); + var streamFs = File.OpenRead(reiaPath); reia = ReiaFile.Read(streamFs, stream); } void Reload() { reia.Dispose(); - var realPath = Filesystem.GetRealPath(reiaPath); - var streamFs = File.OpenRead(realPath); + var streamFs = File.OpenRead(reiaPath); reia = ReiaFile.Read(streamFs, stream); reload = false; frameCounter = 0f; diff --git a/Assets/Scripts/OpenTS2/Engine/Tests/ScenegraphGMDCTest.cs b/Assets/Scripts/OpenTS2/Engine/Tests/ScenegraphGMDCTest.cs index 9db32258..0098fa53 100644 --- a/Assets/Scripts/OpenTS2/Engine/Tests/ScenegraphGMDCTest.cs +++ b/Assets/Scripts/OpenTS2/Engine/Tests/ScenegraphGMDCTest.cs @@ -2,6 +2,7 @@ using OpenTS2.Components; using OpenTS2.Content; using OpenTS2.Content.DBPF.Scenegraph; +using OpenTS2.Engine; using OpenTS2.Files; using OpenTS2.Files.Formats.DBPF; using UnityEngine; @@ -10,15 +11,17 @@ public class ScenegraphGMDCTest : MonoBehaviour { private void Start() { - var contentProvider = ContentProvider.Get(); + Core.InitializeCore(); + + var contentManager = ContentManager.Instance; // Load base game assets. - contentProvider.AddPackages( - Filesystem.GetPackagesInDirectory(Filesystem.GetDataPathForProduct(ProductFlags.BaseGame) + "/Res/Sims3D")); + contentManager.AddPackages( + Filesystem.GetPackagesInDirectory(Filesystem.GetPathForProduct(ProductFlags.BaseGame) + "TSData/Res/Sims3D")); //var resourceName = "vehiclePizza_cres"; var resourceName = "chairReclinerPuffy_cres"; - var resource = contentProvider.GetAsset( + var resource = contentManager.GetAsset( new ResourceKey(resourceName, GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_CRES)); Debug.Log($"scenegraphModel: {resource.GlobalTGI}"); @@ -35,17 +38,17 @@ private static void AddAnimations(GameObject gameObject) var anim = gameObject.GetComponentInChildren(); var scenegraphComponent = gameObject.GetComponentInChildren(); - var driveOff = ContentProvider.Get().GetAsset( + var driveOff = ContentManager.Instance.GetAsset( new ResourceKey("o-vehiclePizza-driveOff_anim", GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_ANIM)); var clip = driveOff.CreateClipFromResource(scenegraphComponent.BoneNamesToRelativePaths, scenegraphComponent.BlendNamesToRelativePaths); anim.AddClip(clip, "driveOff"); - var drive = ContentProvider.Get().GetAsset( + var drive = ContentManager.Instance.GetAsset( new ResourceKey("o-vehiclePizza-drive_anim", GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_ANIM)); clip = drive.CreateClipFromResource(scenegraphComponent.BoneNamesToRelativePaths, scenegraphComponent.BlendNamesToRelativePaths); anim.AddClip(clip, "drive"); - var stop = ContentProvider.Get().GetAsset( + var stop = ContentManager.Instance.GetAsset( new ResourceKey("o-vehiclePizza-stop_anim", GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_ANIM)); clip = stop.CreateClipFromResource(scenegraphComponent.BoneNamesToRelativePaths, scenegraphComponent.BlendNamesToRelativePaths); anim.AddClip(clip, "stop"); @@ -56,7 +59,7 @@ private static void AddChairAnimations(GameObject gameObject) var anim = gameObject.GetComponentInChildren(); var scenegraphComponent = gameObject.GetComponentInChildren(); - var recline = ContentProvider.Get().GetAsset( + var recline = ContentManager.Instance.GetAsset( new ResourceKey("o2a-chairRecliner-recline_anim", GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_ANIM)); var clip = recline.CreateClipFromResource(scenegraphComponent.BoneNamesToRelativePaths, scenegraphComponent.BlendNamesToRelativePaths); anim.AddClip(clip, "recline"); diff --git a/Assets/Scripts/OpenTS2/Engine/Tests/SimAnimationTest.cs b/Assets/Scripts/OpenTS2/Engine/Tests/SimAnimationTest.cs index 5adff6f6..94563b9d 100644 --- a/Assets/Scripts/OpenTS2/Engine/Tests/SimAnimationTest.cs +++ b/Assets/Scripts/OpenTS2/Engine/Tests/SimAnimationTest.cs @@ -8,6 +8,7 @@ using OpenTS2.Files; using OpenTS2.Files.Formats.DBPF; using UnityEngine; +using System.IO; namespace OpenTS2.Engine.Tests { @@ -24,15 +25,16 @@ public class SimAnimationTest : MonoBehaviour private void Start() { - var contentProvider = ContentProvider.Get(); + Core.InitializeCore(); + var contentManager = ContentManager.Instance; // Load base game assets. - contentProvider.AddPackages( - Filesystem.GetPackagesInDirectory(Filesystem.GetDataPathForProduct(ProductFlags.BaseGame) + - "/Res/Sims3D")); + contentManager.AddPackages( + Filesystem.GetPackagesInDirectory(Path.Combine(Filesystem.GetPathForProduct(ProductFlags.BaseGame), + "TSData/Res/Sims3D"))); // Load all animations involving auskel and put them in the dictionary. - foreach (var animationAsset in contentProvider.GetAssetsOfType(TypeIDs.SCENEGRAPH_ANIM)) + foreach (var animationAsset in contentManager.GetAssetsOfType(TypeIDs.SCENEGRAPH_ANIM)) { var auSkelTarget = animationAsset.AnimResource.AnimTargets.FirstOrDefault(t => t.TagName.ToLower() == "auskel"); if (auSkelTarget == null) @@ -47,7 +49,7 @@ private void Start() _sim = SimCharacterComponent.CreateNakedBaseSim(); const string animationName = "a-pose-neutral-stand_anim"; - var anim = contentProvider.GetAsset( + var anim = contentManager.GetAsset( new ResourceKey(animationName, GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_ANIM)); _sim.AdjustInverseKinematicWeightsForAnimation(anim.AnimResource); @@ -58,7 +60,7 @@ private void Start() //const string testAnimation = "a-blowHorn_anim"; const string testAnimation = "a2o-punchingBag-punch-start_anim"; - anim = contentProvider.GetAsset( + anim = contentManager.GetAsset( new ResourceKey(testAnimation, GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_ANIM)); clip = anim.CreateClipFromResource(_sim.Scenegraph.BoneNamesToRelativePaths, _sim.Scenegraph.BlendNamesToRelativePaths); _animationObj.AddClip(clip, testAnimation); diff --git a/Assets/Scripts/OpenTS2/Engine/Tests/TerrainTestScript.cs b/Assets/Scripts/OpenTS2/Engine/Tests/TerrainTestScript.cs index d0cff01f..c67b0d6f 100644 --- a/Assets/Scripts/OpenTS2/Engine/Tests/TerrainTestScript.cs +++ b/Assets/Scripts/OpenTS2/Engine/Tests/TerrainTestScript.cs @@ -16,14 +16,14 @@ public class TerrainTestScript : MonoBehaviour // Start is called before the first frame update void Start() { - var contentProvider = ContentProvider.Get(); - contentProvider.AddPackage(PackageToLoad); + var contentManager = ContentManager.Instance; + contentManager.AddPackage(PackageToLoad); // Use N001_Neighborhood etc as the group name. var groupName = Path.GetFileNameWithoutExtension(PackageToLoad); var terrainAsset = - contentProvider.GetAsset( + contentManager.GetAsset( new ResourceKey(0x0, groupName, TypeIDs.NHOOD_TERRAIN)); //terrainAsset.ApplyToTerrain(terrain); terrainMeshFilter.sharedMesh = terrainAsset.MakeMesh(); diff --git a/Assets/Scripts/OpenTS2/Engine/Tests/UILayoutTest.cs b/Assets/Scripts/OpenTS2/Engine/Tests/UILayoutTest.cs index 0b4b2c44..7b217865 100644 --- a/Assets/Scripts/OpenTS2/Engine/Tests/UILayoutTest.cs +++ b/Assets/Scripts/OpenTS2/Engine/Tests/UILayoutTest.cs @@ -1,5 +1,4 @@ -using OpenTS2.Client; -using OpenTS2.Common; +using OpenTS2.Common; using OpenTS2.Content; using OpenTS2.Files; using OpenTS2.Files.Formats.DBPF; @@ -20,40 +19,32 @@ public class UILayoutTest : MonoBehaviour public string Key = "0x49001017"; public bool Reload = false; public bool LoadPackagesFromAllEPs = true; - private readonly string RelativeUIPackagePath = "Res/UI/ui.package"; private List _instances = new List(); void LoadAllUIPackages() { - EPManager.Get().InstalledProducts = 0x3EFFF; + EPManager.Instance.InstalledProducts = 0x3EFFF; ContentLoading.LoadContentStartup(); } void LoadBGUIPackage() { - EPManager.Get().InstalledProducts = (int)ProductFlags.BaseGame; + EPManager.Instance.InstalledProducts = (int)ProductFlags.BaseGame; ContentLoading.LoadContentStartup(); } void CreateUI() { - try + var globals = GameGlobals.Instance; + globals.Language = Language; + foreach (var instance in _instances) { - var settings = Settings.Get(); - settings.Language = Language; - foreach (var instance in _instances) - { - Destroy(instance.gameObject); - } - _instances.Clear(); - var contentProvider = ContentProvider.Get(); - var key = new ResourceKey(Convert.ToUInt32(Key, 16), 0xA99D8A11, TypeIDs.UI); - var uiLayout = contentProvider.GetAsset(key); - _instances.AddRange(uiLayout.Instantiate(UIManager.MainCanvas.transform)); - } - catch(Exception e) - { - Debug.LogError(e); + Destroy(instance.gameObject); } + _instances.Clear(); + var contentManager = ContentManager.Instance; + var key = new ResourceKey(Convert.ToUInt32(Key, 16), 0xA99D8A11, TypeIDs.UI); + var uiLayout = contentManager.GetAsset(key); + _instances.AddRange(uiLayout.Instantiate(UIManager.MainCanvas.transform)); } private void Update() @@ -75,15 +66,15 @@ private void Update() private void Start() { - var settings = Settings.Get(); - settings.CustomContentEnabled = false; + GameGlobals.allowCustomContent = false; if (LoadPackagesFromAllEPs) LoadAllUIPackages(); else LoadBGUIPackage(); + Core.OnFinishedLoading?.Invoke(); CreateUI(); /* - var contentProvider = ContentProvider.Get(); + var contentManager = ContentManager.Get(); // Main Menu //var key = new ResourceKey(0x49001017, 0xA99D8A11, TypeIDs.UI); // Neighborhood View @@ -91,7 +82,7 @@ private void Start() //var key = new ResourceKey(0x49001010, 0xA99D8A11, TypeIDs.UI); //var key = new ResourceKey(0x49060005, 0xA99D8A11, TypeIDs.UI); //var key = new ResourceKey(0x49001024, 0xA99D8A11, TypeIDs.UI); - var mainMenuUILayout = contentProvider.GetAsset(key); + var mainMenuUILayout = contentManager.GetAsset(key); _instances.AddRange(mainMenuUILayout.Instantiate(Canvas));*/ } } diff --git a/Assets/Scripts/OpenTS2/Engine/Tests/UITest.cs b/Assets/Scripts/OpenTS2/Engine/Tests/UITest.cs index 5bc90d8b..b57e8392 100644 --- a/Assets/Scripts/OpenTS2/Engine/Tests/UITest.cs +++ b/Assets/Scripts/OpenTS2/Engine/Tests/UITest.cs @@ -24,16 +24,16 @@ public class UITest : MonoBehaviour void Start() { - var contentProvider = ContentProvider.Get(); - contentProvider.AddPackage(PackageToLoad); + var contentManager = ContentManager.Instance; + contentManager.AddPackage(PackageToLoad); var resKey = new ResourceKey(0x00000001, "N001_FamilyThumbnails", 0x8C3CE95A); - var hasFile = contentProvider.GetEntry(resKey); + var hasFile = contentManager.GetEntry(resKey); if (hasFile == null) { Debug.Log("CANT FIND FILE!"); return; } - var texture = contentProvider.GetAsset(resKey); + var texture = contentManager.GetAsset(resKey); Image.texture = texture.Texture; } } diff --git a/Assets/Scripts/OpenTS2/Files/Filesystem.cs b/Assets/Scripts/OpenTS2/Files/Filesystem.cs index dca6e130..13aa590a 100644 --- a/Assets/Scripts/OpenTS2/Files/Filesystem.cs +++ b/Assets/Scripts/OpenTS2/Files/Filesystem.cs @@ -13,6 +13,8 @@ using OpenTS2.Content.Interfaces; using OpenTS2.Common.Utils; using OpenTS2.Content; +using OpenTS2.Lua.Disassembly.OpCodes; +using UnityEngine; namespace OpenTS2.Files { @@ -21,36 +23,57 @@ namespace OpenTS2.Files /// public static class Filesystem { - static IPathProvider s_pathProvider; - static EPManager s_epManager; + [Serializable] + private class JSONConfig + { + public string game_dir; + public string user_dir; + public List dlc; + } - public static IPathProvider PathProvider => s_pathProvider; + public static string GameDirectory { get; private set; } + public static string UserDataDirectory { get; private set; } + public static List ProductDirectories { get; private set; } - static string UserDataDirectory + public static void Initialize() { - get { return "%UserDataDir%"; } + ProductDirectories = new List(); } - static string DataDirectory + public static void InitializeFromJSON(string jsonPath) { - get { return "%DataDirectory%"; } + ProductDirectories = new List(); + var config = JsonUtility.FromJson(File.ReadAllText(jsonPath)); + GameDirectory = config.game_dir; + UserDataDirectory = config.user_dir; + foreach(var product in config.dlc) + { + ProductDirectories.Add(Path.Combine(config.game_dir, product)); + } } - static string BinDirectory + public static List GetProductDirectories() { - get { return "%BinDirectory%"; } + var epManager = EPManager.Instance; + var products = epManager.GetInstalledProducts(); + var result = new List(); + foreach(var product in products) + { + result.Add(GetPathForProduct(product)); + } + result.Add(Environment.CurrentDirectory); + return result; } - public static void Initialize(IPathProvider pathProvider, EPManager EPManager) + public static string GetPathForProduct(ProductFlags productFlag) { - s_pathProvider = pathProvider; - s_epManager = EPManager; + var index = Array.IndexOf(Enum.GetValues(productFlag.GetType()), productFlag); + return ProductDirectories[index]; } public static List GetStartupDownloadPackages() { - var userPath = s_pathProvider.GetUserPath(); - var downloadsPath = Path.Combine(userPath, "Downloads"); + var downloadsPath = Path.Combine(UserDataDirectory, "Downloads"); var packages = GetPackagesInDirectory(downloadsPath); packages = packages.Where(x => FileUtils.CleanPath(x).ToLowerInvariant().Contains("/startup/")).ToList(); return packages; @@ -58,8 +81,7 @@ public static List GetStartupDownloadPackages() public static List GetStreamedDownloadPackages() { - var userPath = s_pathProvider.GetUserPath(); - var downloadsPath = Path.Combine(userPath, "Downloads"); + var downloadsPath = Path.Combine(UserDataDirectory, "Downloads"); var packages = GetPackagesInDirectory(downloadsPath); packages = packages.Where(x => !FileUtils.CleanPath(x).ToLowerInvariant().Contains("/startup/")).ToList(); return packages; @@ -67,8 +89,7 @@ public static List GetStreamedDownloadPackages() public static List GetUserPackages() { - var userPath = s_pathProvider.GetUserPath(); - var packageList = RemoveNeighborhoodAndCCPackagesFromList(GetPackagesInDirectory(userPath)); + var packageList = RemoveNeighborhoodAndCCPackagesFromList(GetPackagesInDirectory(UserDataDirectory)); return packageList; } @@ -80,12 +101,12 @@ public static List GetPackagesForNeighborhood(Neighborhood neighborhood) return packages; } - static List RemoveNeighborhoodAndCCPackagesFromList(List packages) + private static List RemoveNeighborhoodAndCCPackagesFromList(List packages) { return packages.Where(x => !IsNeighborhoodPackage(x) && !IsDownloadPackage(x)).ToList(); } - static bool IsDownloadPackage(string filename) + private static bool IsDownloadPackage(string filename) { var clean = FileUtils.CleanPath(filename).ToLowerInvariant(); if (clean.Contains("/downloads/")) @@ -93,7 +114,7 @@ static bool IsDownloadPackage(string filename) return false; } - static bool IsNeighborhoodPackage(string filename) + private static bool IsNeighborhoodPackage(string filename) { var clean = FileUtils.CleanPath(filename).ToLowerInvariant(); if (clean.Contains("/neighborhoods/")) @@ -113,13 +134,12 @@ static bool IsNeighborhoodPackage(string filename) public static List GetStartupPackages() { var startupList = new List(); - var productList = s_epManager.GetInstalledProducts(); + var productList = GetProductDirectories(); foreach(var product in productList) { - var dataPath = s_pathProvider.GetDataPathForProduct(product); - var uiPath = Path.Combine(dataPath, "Res/UI"); - var textPath = Path.Combine(dataPath, "Res/Text"); - var soundPath = Path.Combine(dataPath, "Res/Sound"); + var uiPath = Path.Combine(product, "TSData/Res/UI"); + var textPath = Path.Combine(product, "TSData/Res/Text"); + var soundPath = Path.Combine(product, "TSData/Res/Sound"); startupList.AddRange(GetPackagesInDirectory(uiPath)); startupList.AddRange(GetPackagesInDirectory(textPath)); startupList.AddRange(GetPackagesInDirectory(soundPath)); @@ -130,21 +150,29 @@ public static List GetStartupPackages() public static List GetMainPackages() { var mainList = new List(); - var productList = s_epManager.GetInstalledProducts(); + var productList = GetProductDirectories(); + var curProduct = 0; + + var globalLots = new List(); + var lotTemplates = new List(); + var materials = new List(); + var objects = new List(); + var objectScripts = new List(); + var wants = new List(); + foreach (var product in productList) { + curProduct++; + var catalogPath = Path.Combine(product, "TSData/Res/Catalog"); + var effectsPath = Path.Combine(product, "TSData/Res/Effects"); - var dataPath = s_pathProvider.GetDataPathForProduct(product); - var catalogPath = Path.Combine(dataPath, "Res/Catalog"); - var effectsPath = Path.Combine(dataPath, "Res/Effects"); - - var sims3dPath = Path.Combine(dataPath, "Res/Sims3D"); - var threedPath = Path.Combine(dataPath, "Res/3D"); - var terrainPath = Path.Combine(dataPath, "Res/Terrain"); - var overridesPath = Path.Combine(dataPath, "Res/Overrides"); - var stuffPackPath = Path.Combine(dataPath, "Res/StuffPack"); + var sims3dPath = Path.Combine(product, "TSData/Res/Sims3D"); + var threedPath = Path.Combine(product, "TSData/Res/3D"); + var terrainPath = Path.Combine(product, "TSData/Res/Terrain"); + var overridesPath = Path.Combine(product, "TSData/Res/Overrides"); + var stuffPackPath = Path.Combine(product, "TSData/Res/StuffPack"); - var lightingPath = Path.Combine(dataPath, "Res/Lighting"); + var lightingPath = Path.Combine(product, "TSData/Res/Lighting"); mainList.AddRange(GetPackagesInDirectory(catalogPath)); mainList.AddRange(GetPackagesInDirectory(effectsPath)); @@ -157,22 +185,36 @@ public static List GetMainPackages() mainList.AddRange(GetPackagesInDirectory(lightingPath)); - if (s_epManager.GetLatestProduct() == product) - { - var globalLotsPath = Path.Combine(dataPath, "Res/GlobalLots"); - mainList.AddRange(GetPackagesInDirectory(globalLotsPath)); - var lotTemplatesPath = Path.Combine(dataPath, "Res/LotTemplates"); - mainList.AddRange(GetPackagesInDirectory(lotTemplatesPath)); - var materialsPath = Path.Combine(dataPath, "Res/Materials"); - mainList.AddRange(GetPackagesInDirectory(materialsPath)); - var objectsPath = Path.Combine(dataPath, "Res/Objects"); - mainList.AddRange(GetPackagesInDirectory(objectsPath)); - var objectScriptsPath = Path.Combine(dataPath, "Res/ObjectScripts"); - mainList.AddRange(GetPackagesInDirectory(objectScriptsPath)); - var wantsPath = Path.Combine(dataPath, "Res/Wants"); - mainList.AddRange(GetPackagesInDirectory(wantsPath)); - } + var globalLotsPath = Path.Combine(product, "TSData/Res/GlobalLots"); + if (Directory.Exists(globalLotsPath)) + globalLots = GetPackagesInDirectory(globalLotsPath); + + var lotTemplatesPath = Path.Combine(product, "TSData/Res/LotTemplates"); + if (Directory.Exists(lotTemplatesPath)) + lotTemplates = GetPackagesInDirectory(lotTemplatesPath); + + var materialsPath = Path.Combine(product, "TSData/Res/Materials"); + if (Directory.Exists(materialsPath)) + materials = GetPackagesInDirectory(materialsPath); + + var objectsPath = Path.Combine(product, "TSData/Res/Objects"); + if (Directory.Exists(objectsPath)) + objects = GetPackagesInDirectory(objectsPath); + + var objectScriptsPath = Path.Combine(product, "TSData/Res/ObjectScripts"); + if (Directory.Exists(objectScriptsPath)) + objectScripts = GetPackagesInDirectory(objectScriptsPath); + + var wantsPath = Path.Combine(product, "TSData/Res/Wants"); + if (Directory.Exists(wantsPath)) + wants = GetPackagesInDirectory(wantsPath); } + mainList.AddRange(globalLots); + mainList.AddRange(lotTemplates); + mainList.AddRange(materials); + mainList.AddRange(objects); + mainList.AddRange(objectScripts); + mainList.AddRange(wants); return mainList; } @@ -200,109 +242,23 @@ public static List GetPackagesInDirectory(string directory) return GetFilesInPath(".package", directory); } - public static string GetPathForProduct(ProductFlags product) - { - return s_pathProvider.GetPathForProduct(product); - } - - public static string GetDataPathForProduct(ProductFlags product) - { - return s_pathProvider.GetDataPathForProduct(product); - } - - public static string GetBinPathForProduct(ProductFlags product) - { - return s_pathProvider.GetBinPathForProduct(product); - } - - public static string GetUserPath() - { - return s_pathProvider.GetUserPath(); - } - /// - /// Given a file path relative to TSData, tries to find the absolute path to the file in the latest installed product where the file is available. - /// For example, given "Res/UI/Fonts/FontStyle.ini" in an unmodified installation with all products, this would return the University path, as it's the newest EP that has this file. + /// Given a file path relative to a product, tries to find the absolute path to the file in the latest installed product where the file is available. + /// For example, given "TSData/Res/UI/Fonts/FontStyle.ini" in an unmodified installation with all products, this would return the University path, as it's the newest EP that has this file. /// /// File path relative to TSData /// Absolute file path. Null if file can't be found in any Product. public static string GetLatestFilePath(string filepath) { - var installedProducts = s_epManager.GetInstalledProducts(); + var installedProducts = GetProductDirectories(); for (var i = installedProducts.Count - 1; i >= 0; i--) { - var dataPath = GetDataPathForProduct(installedProducts[i]); + var dataPath = installedProducts[i]; var absolutePath = Path.Combine(dataPath, filepath); if (File.Exists(absolutePath)) return absolutePath; } return null; } - - /// - /// Checks if two paths, unparsed or parsed, are equal. - /// - /// Path to check - /// Path to check against - /// True if equal, false if not. - public static bool PathsEqual(string path1, string path2) - { - path1 = GetRealPath(path1).ToLowerInvariant(); - path2 = GetRealPath(path2).ToLowerInvariant(); - return (path1 == path2); - } - /// - /// Returns short relative path. (Eg. Replaces the game's directory with the %DataDirectory% shorthand) - /// - /// Path to shorten - /// Fake short path - public static string GetShortPath(string path) - { - path = FileUtils.CleanPath(path) + "/"; - path = path.Replace(s_pathProvider.GetDataPathForProduct(s_epManager.GetLatestProduct()), DataDirectory); - path = path.Replace(s_pathProvider.GetUserPath(), UserDataDirectory); - path = path.Replace(s_pathProvider.GetBinPathForProduct(s_epManager.GetLatestProduct()), BinDirectory); - path = FileUtils.CleanPath(path); - return path; - } - - /// - /// Returns fully parsed path. (Eg. Replaces %DataDirectory% with actual data directory path) - /// - /// Path to parse - /// Real path - public static string GetRealPath(string path) - { - path = path.Replace(DataDirectory, s_pathProvider.GetDataPathForProduct(s_epManager.GetLatestProduct())); - path = path.Replace(UserDataDirectory, s_pathProvider.GetUserPath()); - path = path.Replace(BinDirectory, s_pathProvider.GetBinPathForProduct(s_epManager.GetLatestProduct())); - path = FileUtils.CleanPath(path); - return path; - } - - /// - /// Writes a byte array into a file, creating all necessary directories. - /// - /// Path to output file. - /// Byte array to write. - public static void Write(string path, byte[] bytes) - { - Write(path, bytes, bytes.Length); - } - - /// - /// Writes a byte array into a file, creating all necessary directories. - /// - /// Path to output file. - /// Byte array to write. - public static void Write(string path, byte[] bytes, int size) - { - var dir = Path.GetDirectoryName(path); - if (!Directory.Exists(dir) && !string.IsNullOrEmpty(dir)) - Directory.CreateDirectory(dir); - var fStream = new FileStream(path, FileMode.Create, FileAccess.Write); - fStream.Write(bytes, 0, size); - fStream.Dispose(); - } } } diff --git a/Assets/Scripts/OpenTS2/Files/Formats/DBPF/MP3Codec.cs b/Assets/Scripts/OpenTS2/Files/Formats/DBPF/AudioCodec.cs similarity index 69% rename from Assets/Scripts/OpenTS2/Files/Formats/DBPF/MP3Codec.cs rename to Assets/Scripts/OpenTS2/Files/Formats/DBPF/AudioCodec.cs index a1c50f39..5e7150a4 100644 --- a/Assets/Scripts/OpenTS2/Files/Formats/DBPF/MP3Codec.cs +++ b/Assets/Scripts/OpenTS2/Files/Formats/DBPF/AudioCodec.cs @@ -15,21 +15,22 @@ using System.Text; using OpenTS2.Files.Formats.XA; using OpenTS2.Files.Formats.UTK; +using OpenTS2.Files.Formats.SPX; namespace OpenTS2.Files.Formats.DBPF { /// - /// MP3 or XA audio reading code. + /// Audio reading code. /// - [Codec(TypeIDs.MP3)] - public class MP3Codec : AbstractCodec + [Codec(TypeIDs.AUDIO)] + public class AudioCodec : AbstractCodec { /// /// Constructs a new MP3 instance. /// - public MP3Codec() + public AudioCodec() { } @@ -41,20 +42,26 @@ public MP3Codec() public override AbstractAsset Deserialize(byte[] bytes, ResourceKey tgi, DBPFFile sourceFile) { var magic = Encoding.UTF8.GetString(bytes, 0, 2); - byte[] data = new byte[] { }; + var data = bytes; switch(magic) { case "XA": var xa = new XAFile(bytes); data = xa.DecompressedData; - break; + return new WAVAudioAsset(data); case "UT": var utk = new UTKFile(bytes); utk.UTKDecode(); data = utk.DecompressedWav; - break; + return new WAVAudioAsset(data); + case "SP": + var spx = new SPXFile(bytes); + data = spx.DecompressedData; + return new WAVAudioAsset(data); + case "RI": + return new WAVAudioAsset(data); } - return new AudioAsset(data); + return new MP3AudioAsset(data); } } } \ No newline at end of file diff --git a/Assets/Scripts/OpenTS2/Files/Formats/DBPF/MP3Codec.cs.meta b/Assets/Scripts/OpenTS2/Files/Formats/DBPF/AudioCodec.cs.meta similarity index 100% rename from Assets/Scripts/OpenTS2/Files/Formats/DBPF/MP3Codec.cs.meta rename to Assets/Scripts/OpenTS2/Files/Formats/DBPF/AudioCodec.cs.meta diff --git a/Assets/Scripts/OpenTS2/Files/Formats/DBPF/BaseLotInfoCodec.cs b/Assets/Scripts/OpenTS2/Files/Formats/DBPF/BaseLotInfoCodec.cs new file mode 100644 index 00000000..4d8954bf --- /dev/null +++ b/Assets/Scripts/OpenTS2/Files/Formats/DBPF/BaseLotInfoCodec.cs @@ -0,0 +1,32 @@ +using OpenTS2.Common; +using OpenTS2.Content.DBPF; +using OpenTS2.Content; +using OpenTS2.Files.Utils; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OpenTS2.Files.Formats.DBPF +{ + [Codec(TypeIDs.BASE_LOT_INFO)] + public class BaseLotInfoCodec : AbstractCodec + { + public override AbstractAsset Deserialize(byte[] bytes, ResourceKey tgi, DBPFFile sourceFile) + { + using var stream = new MemoryStream(bytes); + using var reader = IoBuffer.FromStream(stream, ByteOrder.LITTLE_ENDIAN); + + var filename = reader.ReadNullTerminatedUTF8(); + reader.Seek(SeekOrigin.Begin, 64); + + // Inside the lotInfo is a nested baseLotInfo that carries information about the original lot. + var baseLotInfo = new BaseLotInfo(); + baseLotInfo.Read(reader, false); + + return new BaseLotInfoAsset(filename, baseLotInfo); + } + } +} diff --git a/Assets/Scripts/OpenTS2/Files/Formats/DBPF/BaseLotInfoCodec.cs.meta b/Assets/Scripts/OpenTS2/Files/Formats/DBPF/BaseLotInfoCodec.cs.meta new file mode 100644 index 00000000..1e4fba13 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Files/Formats/DBPF/BaseLotInfoCodec.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 38f3fc5209dc5d8468aca4df0b6c77f1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Files/Formats/DBPF/Codecs.cs b/Assets/Scripts/OpenTS2/Files/Formats/DBPF/Codecs.cs index 438c189c..e09e70e9 100644 --- a/Assets/Scripts/OpenTS2/Files/Formats/DBPF/Codecs.cs +++ b/Assets/Scripts/OpenTS2/Files/Formats/DBPF/Codecs.cs @@ -19,7 +19,7 @@ namespace OpenTS2.Files.Formats.DBPF public static class Codecs { //AbstractCodec classes with CodecAttributes should be automatically added here. - static readonly Dictionary s_codecsByTypeID = new Dictionary(); + static readonly Dictionary CodecByTypeID = new Dictionary(); /// /// Register a codec. @@ -28,7 +28,7 @@ public static class Codecs /// Codec instance. public static void Register(uint type, AbstractCodec codec) { - s_codecsByTypeID[type] = codec; + CodecByTypeID[type] = codec; } /// @@ -38,7 +38,7 @@ public static void Register(uint type, AbstractCodec codec) /// Codec for this type. public static AbstractCodec Get(uint type) { - if (s_codecsByTypeID.TryGetValue(type, out AbstractCodec codecOut)) + if (CodecByTypeID.TryGetValue(type, out AbstractCodec codecOut)) return codecOut; return null; } diff --git a/Assets/Scripts/OpenTS2/Files/Formats/DBPF/DBPFFile.cs b/Assets/Scripts/OpenTS2/Files/Formats/DBPF/DBPFFile.cs index 8abd9a3c..f2978c13 100644 --- a/Assets/Scripts/OpenTS2/Files/Formats/DBPF/DBPFFile.cs +++ b/Assets/Scripts/OpenTS2/Files/Formats/DBPF/DBPFFile.cs @@ -29,11 +29,11 @@ public class DBPFFile : IDisposable public class DBPFFileChanges { private readonly DBPFFile _owner; - private ContentProvider Provider + private ContentManager Manager { get { - return _owner.Provider; + return _owner.Manager; } } @@ -52,7 +52,7 @@ public DBPFFileChanges(DBPFFile owner) /// public void Delete() { - Provider?.RemoveFromResourceMap(_owner); + Manager?.RemoveFromResourceMap(_owner); var entries = _owner.Entries; foreach(var element in entries) { @@ -67,22 +67,22 @@ public void Delete() /// public void Clear() { - Provider?.RemoveFromResourceMap(_owner); + Manager?.RemoveFromResourceMap(_owner); DeletedEntries.Clear(); ChangedEntries.Clear(); Dirty = false; - Provider?.UpdateOrAddToResourceMap(_owner); + Manager?.UpdateOrAddToResourceMap(_owner); RefreshCache(); } void RefreshCache() { - Provider?.Cache.RemoveAllForPackage(_owner); + Manager?.Cache.RemoveAllForPackage(_owner); } void RefreshCache(ResourceKey tgi) { - Provider?.Cache.Remove(tgi, _owner); + Manager?.Cache.Remove(tgi, _owner); } /// @@ -93,7 +93,7 @@ public void Delete(DBPFEntry entry) { DeletedEntries[entry.TGI] = true; Dirty = true; - Provider?.RemoveFromResourceMap(entry); + Manager?.RemoveFromResourceMap(entry); RefreshCache(entry.TGI); } @@ -107,7 +107,7 @@ public void Restore(DBPFEntry entry) { DeletedEntries.Remove(entry.TGI); Dirty = true; - Provider?.UpdateOrAddToResourceMap(entry); + Manager?.UpdateOrAddToResourceMap(entry); RefreshCache(entry.TGI); } } @@ -120,7 +120,7 @@ public void Delete(ResourceKey tgi) { DeletedEntries[tgi] = true; Dirty = true; - Provider?.RemoveFromResourceMap(tgi.LocalGroupID(_owner.GroupID), _owner); + Manager?.RemoveFromResourceMap(tgi.LocalGroupID(_owner.GroupID), _owner); RefreshCache(tgi); } /// @@ -133,7 +133,7 @@ public void Restore(ResourceKey tgi) { DeletedEntries.Remove(tgi); Dirty = true; - Provider?.UpdateOrAddToResourceMap(_owner.GetEntryByTGI(tgi)); + Manager?.UpdateOrAddToResourceMap(_owner.GetEntryByTGI(tgi)); RefreshCache(tgi); } } @@ -168,7 +168,7 @@ public void Set(AbstractAsset asset) ChangedEntries[asset.TGI] = changedEntry; InternalRestore(asset.TGI); Dirty = true; - Provider?.UpdateOrAddToResourceMap(changedEntry); + Manager?.UpdateOrAddToResourceMap(changedEntry); RefreshCache(asset.TGI); } /// @@ -188,7 +188,7 @@ public void Set(byte[] bytes, ResourceKey tgi, bool compressed) ChangedEntries[tgi] = changedEntry; InternalRestore(tgi); Dirty = true; - Provider?.UpdateOrAddToResourceMap(changedEntry); + Manager?.UpdateOrAddToResourceMap(changedEntry); RefreshCache(tgi); } @@ -209,7 +209,7 @@ public void SetCompressed(DBPFEntry entry, bool compressed) ChangedEntries[entry.TGI] = changedEntry; InternalRestore(entry.TGI); Dirty = true; - Provider?.UpdateOrAddToResourceMap(changedEntry); + Manager?.UpdateOrAddToResourceMap(changedEntry); RefreshCache(entry.TGI); } } @@ -228,7 +228,7 @@ public bool Deleted bool _deleted = false; public bool DeleteIfEmpty = true; private DBPFFileChanges _changes; - public ContentProvider Provider = null; + public ContentManager Manager = null; /// /// Holds all runtime modifications in memory. @@ -246,11 +246,11 @@ public string FilePath get { return _filePath; } set { - var oldProvider = Provider; - oldProvider?.RemovePackage(this); + var oldManager = Manager; + oldManager?.RemovePackage(this); _filePath = value; GroupID = FileUtils.GroupHash(Path.GetFileNameWithoutExtension(_filePath)); - oldProvider?.AddPackage(this); + oldManager?.AddPackage(this); } } public int DateCreated; @@ -427,18 +427,36 @@ public void Read(Stream stream) /// public void WriteToFile() { + // Can't read stuff from ourselves if we are writing into ourselves. + var writeDirectly = false; + if (OriginalEntries.Count == 0) + writeDirectly = true; + if (DeleteIfEmpty && Empty) { Dispose(); - Provider?.RemovePackage(this); + Manager?.RemovePackage(this); File.Delete(FilePath); Changes.Clear(); _deleted = true; return; } - var data = Serialize(); - Dispose(); - Filesystem.Write(FilePath, data); + var dir = Path.GetDirectoryName(FilePath); + if (!Directory.Exists(dir) && !string.IsNullOrEmpty(dir)) + Directory.CreateDirectory(dir); + if (writeDirectly) + { + using var fs = new FileStream(FilePath, FileMode.Create); + Serialize(fs); + Dispose(); + } + else + { + using var ms = new MemoryStream(); + Serialize(ms); + Dispose(); + File.WriteAllBytes(FilePath, ms.ToArray()); + } var stream = File.OpenRead(FilePath); Read(stream); _changes = new DBPFFileChanges(this); @@ -449,13 +467,18 @@ public void WriteToFile() /// Serializes package with all resource changes, additions and deletions. /// /// Package bytes - public byte[] Serialize() + public void Serialize(Stream stream) { UpdateDIR(); - var wStream = new MemoryStream(0); - var writer = new BinaryWriter(wStream); + using var writer = new BinaryWriter(stream); + var dirEntry = GetEntryByTGI(ResourceKey.DIR); var dirAsset = GetAssetByTGI(ResourceKey.DIR); var entries = Entries; + if (dirEntry != null) + { + entries.Remove(dirEntry); + entries.Add(dirEntry); + } //HeeeADER writer.Write(new char[] { 'D', 'B', 'P', 'F' }); //major version @@ -477,12 +500,12 @@ public byte[] Serialize() writer.Write((int)entries.Count); //Index offset - var indexOff = wStream.Position; + var indexOff = stream.Position; //Placeholder writer.Write((int)0); //Index size - var indexSize = wStream.Position; + var indexSize = stream.Position; //Placeholder writer.Write((int)0); @@ -497,10 +520,10 @@ public byte[] Serialize() writer.Write(new byte[32]); //Go back and write index offset - var lastPos = wStream.Position; - wStream.Position = indexOff; + var lastPos = stream.Position; + stream.Position = indexOff; writer.Write((int)lastPos); - wStream.Position = lastPos; + stream.Position = lastPos; var entryOffset = new List(); @@ -511,25 +534,25 @@ public byte[] Serialize() writer.Write(element.TGI.GroupID); writer.Write(element.TGI.InstanceID); writer.Write(element.TGI.InstanceHigh); - entryOffset.Add(wStream.Position); + entryOffset.Add(stream.Position); writer.Write(0); //File Size writer.Write(element.FileSize); } - lastPos = wStream.Position; + lastPos = stream.Position; var siz = lastPos - indexOff; - wStream.Position = indexSize; + stream.Position = indexSize; writer.Write((int)siz); - wStream.Position = lastPos; + stream.Position = lastPos; //Write files for (var i = 0; i < entries.Count; i++) { - var filePosition = wStream.Position; - wStream.Position = entryOffset[i]; + var filePosition = stream.Position; + stream.Position = entryOffset[i]; writer.Write((int)filePosition); - wStream.Position = filePosition; + stream.Position = filePosition; var entry = entries[i]; if (!(entry is DynamicDBPFEntry)) { @@ -541,20 +564,26 @@ public byte[] Serialize() var entryData = entry.GetBytes(); if (dirAsset != null && dirAsset.GetUncompressedSize(entry.TGI) != 0) { - entryData = QfsCompression.Compress(entryData, true); - var lastPosition = wStream.Position; - wStream.Position = entryOffset[i] + 4; - writer.Write(entryData.Length); - wStream.Position = lastPosition; + var compressedEntryData = QfsCompression.Compress(entryData, true); + if (compressedEntryData != null) + { + var lastPosition = stream.Position; + stream.Position = entryOffset[i] + 4; + writer.Write(compressedEntryData.Length); + stream.Position = lastPosition; + writer.Write(compressedEntryData, 0, compressedEntryData.Length); + } + else + { + Debug.LogWarning($"Failed to compress resource {entry.TGI} in package {FilePath}. Writing uncompressed."); + writer.Write(entryData, 0, entryData.Length); + dirAsset.SizeByInternalTGI[entry.TGI] = 0; + } } - writer.Write(entryData, 0, entryData.Length); + else + writer.Write(entryData, 0, entryData.Length); } } - - var buffer = StreamUtils.GetBuffer(wStream); - writer.Dispose(); - wStream.Dispose(); - return buffer; } void UpdateDIR() @@ -593,21 +622,24 @@ void UpdateDIR() /// Data for entry. public byte[] GetBytes(DBPFEntry entry, bool ignoreChanges = false) { - if (!ignoreChanges) + lock (_reader) { - if (Changes.DeletedEntries.ContainsKey(entry.TGI)) - return null; - if (Changes.ChangedEntries.ContainsKey(entry.TGI)) - return Changes.ChangedEntries[entry.TGI].Change.Data.GetBytes(); - } - _reader.Seek(SeekOrigin.Begin, entry.FileOffset); - var fileBytes = _reader.ReadBytes((int)entry.FileSize); - var uncompressedSize = InternalGetUncompressedSize(entry); - if (uncompressedSize > 0) - { - return QfsCompression.Decompress(fileBytes); + if (!ignoreChanges) + { + if (Changes.DeletedEntries.ContainsKey(entry.TGI)) + return null; + if (Changes.ChangedEntries.ContainsKey(entry.TGI)) + return Changes.ChangedEntries[entry.TGI].Change.Data.GetBytes(); + } + _reader.Seek(SeekOrigin.Begin, entry.FileOffset); + var fileBytes = _reader.ReadBytes((int)entry.FileSize); + var uncompressedSize = InternalGetUncompressedSize(entry); + if (uncompressedSize > 0) + { + return QfsCompression.Decompress(fileBytes); + } + return fileBytes; } - return fileBytes; } private byte[] GetRawBytes(DBPFEntry entry) diff --git a/Assets/Scripts/OpenTS2/Files/Formats/DBPF/GroupsTypes.cs b/Assets/Scripts/OpenTS2/Files/Formats/DBPF/GroupsTypes.cs index 6d2f2042..d39bf98c 100644 --- a/Assets/Scripts/OpenTS2/Files/Formats/DBPF/GroupsTypes.cs +++ b/Assets/Scripts/OpenTS2/Files/Formats/DBPF/GroupsTypes.cs @@ -34,6 +34,7 @@ public static class TypeIDs public const uint NHOOD_OBJECT = 0x6D619378; // cTSLotInfo in game / Lot Description in SimsPE. public const uint LOT_INFO = 0x0BF999E7; + public const uint BASE_LOT_INFO = 0x6C589723; public const uint LOT_OBJECT = 0xFA1C39F7; public const uint LOT_TERRAIN = 0x6B943B43; public const uint LOT_TEXTURES = 0x4B58975B; @@ -52,21 +53,25 @@ public static class TypeIDs public const uint IMG2 = 0x8C3CE95A; public const uint EFFECTS = 0xEA5118B0; public const uint DIR = 0xE86B1EEF; - /// - /// Can be XA or MP3. - /// - public const uint MP3 = 0x2026960B; + public const uint AUDIO = 0x2026960B; + public const uint OBJ_SAVE_TYPE_TABLE = 0x6f626a74; + /// cTSObject + public const uint XOBJ = 0x584f424a; + /// cEdithObjectModule + public const uint OBJM = 0x4F626A4D; public const uint OBJD = 0x4F424A44; /// dynamiclinklibrary CRC32 hash public const uint DLL = 0x7582DEC6; public const uint CTSS = 0x43545353; public const uint UI = 0x0; public const uint BHAV = 0x42484156; - public const uint SEMIGLOBAL = 0x7F8D70BF; + public const uint SEMIGLOBAL = 0x474C4F42; public const uint LUA_GLOBAL = 0x9012468A; public const uint LUA_LOCAL = 0x9012468B; public const uint OBJF = 0x4F424A66; + public const uint HITLIST = 0x7B1ACFCD; + public const uint NEIGHBOR = 0xAACE2EFB; } public static class GroupIDs { diff --git a/Assets/Scripts/OpenTS2/Files/Formats/DBPF/HitListCodec.cs b/Assets/Scripts/OpenTS2/Files/Formats/DBPF/HitListCodec.cs new file mode 100644 index 00000000..005dbe8b --- /dev/null +++ b/Assets/Scripts/OpenTS2/Files/Formats/DBPF/HitListCodec.cs @@ -0,0 +1,40 @@ +using OpenTS2.Audio; +using OpenTS2.Common; +using OpenTS2.Content; +using OpenTS2.Content.DBPF; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine.Assertions; + +namespace OpenTS2.Files.Formats.DBPF +{ + /// + /// List of audio resources. + /// + [Codec(TypeIDs.HITLIST)] + public class HitListCodec : AbstractCodec + { + public override AbstractAsset Deserialize(byte[] bytes, ResourceKey tgi, DBPFFile sourceFile) + { + using var stream = new MemoryStream(bytes); + using var reader = new BinaryReader(stream); + var version = reader.ReadInt32(); + if (version != 56) + throw new IOException("Unknown HitList version!"); + var soundCount = reader.ReadInt32(); + var sounds = new ResourceKey[soundCount]; + for (var i = 0; i < soundCount; i++) + { + var lowID = reader.ReadUInt32(); + var highID = reader.ReadUInt32(); + var key = AudioManager.Instance.GetAudioResourceKeyByInstanceID(lowID, highID); + sounds[i] = key; + } + return new HitListAsset(sounds); + } + } +} diff --git a/Assets/Scripts/OpenTS2/Files/Formats/DBPF/HitListCodec.cs.meta b/Assets/Scripts/OpenTS2/Files/Formats/DBPF/HitListCodec.cs.meta new file mode 100644 index 00000000..6fd77f2a --- /dev/null +++ b/Assets/Scripts/OpenTS2/Files/Formats/DBPF/HitListCodec.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 322ee634022472640b2f39bca89b3ada +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Files/Formats/DBPF/LotInfoCodec.cs b/Assets/Scripts/OpenTS2/Files/Formats/DBPF/LotInfoCodec.cs index 44988634..7c1bf0d9 100644 --- a/Assets/Scripts/OpenTS2/Files/Formats/DBPF/LotInfoCodec.cs +++ b/Assets/Scripts/OpenTS2/Files/Formats/DBPF/LotInfoCodec.cs @@ -24,46 +24,8 @@ public override AbstractAsset Deserialize(byte[] bytes, ResourceKey tgi, DBPFFil } // Inside the lotInfo is a nested baseLotInfo that carries information about the original lot. - var baseLotInfoVersion = reader.ReadUInt16(); - var creationWidth = reader.ReadUInt32(); - var creationDepth = reader.ReadUInt32(); - var lotType = reader.ReadByte(); - var roadsAlongEdges = reader.ReadByte(); - var creationFrontEdge = reader.ReadByte(); - var flags = (baseLotInfoVersion < 5) ? 0 : reader.ReadUInt32(); - var lotName = ""; - var lotDescription = ""; - if (baseLotInfoVersion > 5) - { - lotName = reader.ReadUint32PrefixedString(); - lotDescription = reader.ReadUint32PrefixedString(); - } - if (baseLotInfoVersion > 3) - { - var lotHeights = new float[reader.ReadUInt32()]; - for (var i = 0; i < lotHeights.Length; i++) - { - lotHeights[i] = reader.ReadFloat(); - } - } - if (baseLotInfoVersion > 6) - { - var creationRoadHeight = reader.ReadFloat(); - } - if (baseLotInfoVersion > 7) - { - // unknown - reader.ReadUInt32(); - } - if (baseLotInfoVersion == 11) - { - var apartmentCount = reader.ReadByte(); - var apartmentRentalPriceHigh = reader.ReadUInt32(); - var apartmentRentalPriceLow = reader.ReadUInt32(); - var lotClass = reader.ReadUInt32(); - var overrideLotClass = reader.ReadByte(); - } - + var baseLotInfo = new BaseLotInfo(); + baseLotInfo.Read(reader, true); // Back to the outer LotInfo. var locationX = reader.ReadUInt32(); var locationY = reader.ReadUInt32(); @@ -75,9 +37,7 @@ public override AbstractAsset Deserialize(byte[] bytes, ResourceKey tgi, DBPFFil // TODO: there's more stuff after this - return new LotInfoAsset(lotId, flags, lotType, lotName, lotDescription, - creationWidth, creationDepth, roadsAlongEdges, locationX, locationY, neighborhoodToLotHeightOffset, - creationFrontEdge, currentFrontEdge); + return new LotInfoAsset(baseLotInfo, lotId, locationX, locationY, neighborhoodToLotHeightOffset, currentFrontEdge); } } } \ No newline at end of file diff --git a/Assets/Scripts/OpenTS2/Files/Formats/DBPF/NeighborCodec.cs b/Assets/Scripts/OpenTS2/Files/Formats/DBPF/NeighborCodec.cs new file mode 100644 index 00000000..7412ac72 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Files/Formats/DBPF/NeighborCodec.cs @@ -0,0 +1,27 @@ +using OpenTS2.Common; +using OpenTS2.Content; +using OpenTS2.Content.DBPF; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OpenTS2.Files.Formats.DBPF +{ + [Codec(TypeIDs.NEIGHBOR)] + public class NeighborCodec : AbstractCodec + { + public override AbstractAsset Deserialize(byte[] bytes, ResourceKey tgi, DBPFFile sourceFile) + { + using var ms = new MemoryStream(bytes); + using var reader = new BinaryReader(ms); + ms.Seek(0x1DC, SeekOrigin.Begin); + var guid = reader.ReadUInt32(); + var neighborId = (short)tgi.InstanceID; + var neighbor = new NeighborAsset((short)tgi.InstanceID, guid); + return neighbor; + } + } +} diff --git a/Assets/Scripts/OpenTS2/Files/Formats/DBPF/NeighborCodec.cs.meta b/Assets/Scripts/OpenTS2/Files/Formats/DBPF/NeighborCodec.cs.meta new file mode 100644 index 00000000..e9a296d7 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Files/Formats/DBPF/NeighborCodec.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ff2577edc2bcdf349ab866ee40a2a200 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Files/Formats/DBPF/ObjectModuleCodec.cs b/Assets/Scripts/OpenTS2/Files/Formats/DBPF/ObjectModuleCodec.cs new file mode 100644 index 00000000..ede32bed --- /dev/null +++ b/Assets/Scripts/OpenTS2/Files/Formats/DBPF/ObjectModuleCodec.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.IO; +using OpenTS2.Common; +using OpenTS2.Content; +using OpenTS2.Content.DBPF; +using OpenTS2.Files.Utils; +using UnityEngine; + +namespace OpenTS2.Files.Formats.DBPF +{ + /// + /// Codec for what is known in game as cEdithObjectModule. Likely a container for different types of objects. + /// + [Codec(TypeIDs.OBJM)] + public class ObjectModuleCodec : AbstractCodec + { + public override AbstractAsset Deserialize(byte[] bytes, ResourceKey tgi, DBPFFile sourceFile) + { + var stream = new MemoryStream(bytes); + var reader = IoBuffer.FromStream(stream, ByteOrder.LITTLE_ENDIAN); + + // Skip first 64 bytes. + reader.Seek(SeekOrigin.Begin, 64); + + // First int, ignored. + reader.Seek(SeekOrigin.Current, 4); + // Version number. + int version = reader.ReadInt32(); + Debug.Log($"Version: 0x{version:X}"); + // Type identifier. + uint type = reader.ReadUInt32(); + if (type != 0x4F626A4D) + { + // Corresponds to the string "ObjM" + throw new NotImplementedException("ObjM file does not have `ObjM` magic bytes"); + } + + var objectIdToSaveType = new Dictionary(); + // Next is the number of objects. + var numObjects = reader.ReadInt32(); + for (var i = 0; i < numObjects; i++) + { + // Data attribute 0x13, might be object id. + int dataAttr = reader.ReadInt32(); + int objectSaveType = reader.ReadInt32(); + objectIdToSaveType[dataAttr] = objectSaveType; + } + + return new ObjectModuleAsset(version: version, objectIdToSaveType: objectIdToSaveType); + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/OpenTS2/Files/Formats/DBPF/ObjectModuleCodec.cs.meta b/Assets/Scripts/OpenTS2/Files/Formats/DBPF/ObjectModuleCodec.cs.meta new file mode 100644 index 00000000..f924f397 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Files/Formats/DBPF/ObjectModuleCodec.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a49ebb5f202a4e24a7d135e40c194bc8 +timeCreated: 1727969785 \ No newline at end of file diff --git a/Assets/Scripts/OpenTS2/Files/Formats/DBPF/ObjectSaveTypeTableCodec.cs b/Assets/Scripts/OpenTS2/Files/Formats/DBPF/ObjectSaveTypeTableCodec.cs new file mode 100644 index 00000000..0fb903a3 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Files/Formats/DBPF/ObjectSaveTypeTableCodec.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using System.IO; +using OpenTS2.Common; +using OpenTS2.Content; +using OpenTS2.Content.DBPF; +using OpenTS2.Files.Utils; +using UnityEngine; + +namespace OpenTS2.Files.Formats.DBPF +{ + [Codec(TypeIDs.OBJ_SAVE_TYPE_TABLE)] + public class ObjectSaveTypeTableCodec : AbstractCodec + { + public override AbstractAsset Deserialize(byte[] bytes, ResourceKey tgi, DBPFFile sourceFile) + { + var stream = new MemoryStream(bytes); + var reader = IoBuffer.FromStream(stream, ByteOrder.LITTLE_ENDIAN); + + // Skip first 64 bytes. + reader.Seek(SeekOrigin.Begin, 64); + + // Spells out "objt" + var id = reader.ReadUInt32(); + if (id != TypeIDs.OBJ_SAVE_TYPE_TABLE) + { + throw new ArgumentException( + $"ObjectSaveTypeTable does not have correct ID: 0x{TypeIDs.OBJ_SAVE_TYPE_TABLE:X}, got: 0x{id:X}"); + } + + var version = reader.ReadUInt32(); + if (version < 0x49) + { + throw new ArgumentException($"ObjectSaveTypeTable version too old: {version}"); + } + // Ignored uint32 + reader.ReadUInt32(); + + // Next up is the selectors. + var selectors = new List(); + while (true) + { + var guid = reader.ReadUInt32(); + if (guid == 0) + { + break; + } + + var initTreeVersion = reader.ReadInt32(); + var mainTreeVersion = reader.ReadInt32(); + // Field 0x3A (maybe NumAttributes) from the object definition. + var numAttributes = reader.ReadInt32(); + // Field 0x3B (maybe NumObjArrays) from the object definition. + var numObjArrays = reader.ReadInt32(); + // The count of some sort of string set related to the object. + var stringSetCount = reader.ReadInt32(); + var saveType = reader.ReadInt16(); + // Field 0x9 (maybe InteractionTableIDPointer) from the object definition. + var interactionTableIDPointer = reader.ReadInt16(); + var catalogResourceName = reader.ReadVariableLengthPascalString(); + // Flags that seem to indicate whether this is a single tile object (bit 0) + // and whether it is a "master" object (bit 1). + var flags = reader.ReadUInt32(); + // Field 0xD0 (unknown) from the object definition. + reader.ReadInt32(); + + selectors.Add(new ObjectSaveTypeTableAsset.ObjectSelector(guid, saveType, catalogResourceName)); + } + + return new ObjectSaveTypeTableAsset(selectors); + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/OpenTS2/Files/Formats/DBPF/ObjectSaveTypeTableCodec.cs.meta b/Assets/Scripts/OpenTS2/Files/Formats/DBPF/ObjectSaveTypeTableCodec.cs.meta new file mode 100644 index 00000000..69a341cb --- /dev/null +++ b/Assets/Scripts/OpenTS2/Files/Formats/DBPF/ObjectSaveTypeTableCodec.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 313c3263408a40c8adbbcc4d40adcda5 +timeCreated: 1728009404 \ No newline at end of file diff --git a/Assets/Scripts/OpenTS2/Files/Formats/DBPF/STRCodec.cs b/Assets/Scripts/OpenTS2/Files/Formats/DBPF/STRCodec.cs index 8ba40867..4b33223b 100644 --- a/Assets/Scripts/OpenTS2/Files/Formats/DBPF/STRCodec.cs +++ b/Assets/Scripts/OpenTS2/Files/Formats/DBPF/STRCodec.cs @@ -14,7 +14,6 @@ using OpenTS2.Content.DBPF; using System.Text; using OpenTS2.Common.Utils; -using OpenTS2.Client; namespace OpenTS2.Files.Formats.DBPF { diff --git a/Assets/Scripts/OpenTS2/Files/Formats/DBPF/SimsObjectCodec.cs b/Assets/Scripts/OpenTS2/Files/Formats/DBPF/SimsObjectCodec.cs new file mode 100644 index 00000000..7b7f583a --- /dev/null +++ b/Assets/Scripts/OpenTS2/Files/Formats/DBPF/SimsObjectCodec.cs @@ -0,0 +1,316 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using OpenTS2.Common; +using OpenTS2.Content; +using OpenTS2.Content.DBPF; +using OpenTS2.Files.Utils; +using UnityEngine; + +namespace OpenTS2.Files.Formats.DBPF +{ + /// + /// Codec for what is known in game as cTSObject. Contains state and locations of objects. + /// + [Codec(TypeIDs.XOBJ)] + public class SimsObjectCodec : AbstractCodec + { + public override AbstractAsset Deserialize(byte[] bytes, ResourceKey tgi, DBPFFile sourceFile) + { + var stream = new MemoryStream(bytes); + var reader = IoBuffer.FromStream(stream, ByteOrder.LITTLE_ENDIAN); + + // This file needs a version that comes from the OBJM file. Without that, just default to 0xAD for now which + // seems to be what my ultimate collection lots are saved with. + return DeserializeWithVersion(reader, version: 0xAD); + } + + public static SimsObjectAsset DeserializeFromBytesAndVersion(byte[] bytes, int version) + { + var stream = new MemoryStream(bytes); + var reader = IoBuffer.FromStream(stream, ByteOrder.LITTLE_ENDIAN); + return DeserializeWithVersion(reader, version); + } + + private static SimsObjectAsset DeserializeWithVersion(IoBuffer reader, int version) + { + // Skip first 64 bytes. + reader.Seek(SeekOrigin.Begin, 64); + + // 4 skipped/unused floats + for (int i = 0; i < 4; i++) + { + reader.ReadFloat(); + } + + var tileLocationY = reader.ReadFloat(); + var tileLocationX = reader.ReadFloat(); + var level = reader.ReadInt32(); + // ignored int16 + reader.ReadUInt16(); + var elevation = reader.ReadFloat(); + var objectGroupId = reader.ReadInt32(); + reader.ReadInt16(); // unknown + if (version > 0xD6) + { + reader.ReadFloat(); // unknown + } + + var numAttrs = reader.ReadInt16(); + var attrs = new short[numAttrs]; + for (var i = 0; i < numAttrs; i++) + { + attrs[i] = reader.ReadInt16(); + } + + var numSemiAttrs = reader.ReadInt16(); + var semiAttrs = new short[numSemiAttrs]; + for (var i = 0; i < numSemiAttrs; i++) + { + semiAttrs[i] = reader.ReadInt16(); + } + + // 8 unknown shorts called "data". + var dataArray = new short[8]; + for (var i = 0; i < dataArray.Length; i++) + { + dataArray[i] = reader.ReadInt16(); + } + + // Next is a number of shorts that depends on the exact version of the file. + uint numShorts = version switch + { + 0xAD => 0x58, + 0xD8 => 0x72, + _ => throw new NotImplementedException($"SimObjectCodec not implemented for version {version:X}"), + }; + + var temp = new short[8]; + for (var i = 0; i < temp.Length; i++) + { + temp[i] = reader.ReadInt16(); + } + var data = new short[numShorts - 8]; + for (var i = 0; i < data.Length; i++) + { + data[i] = reader.ReadInt16(); + } + + // Another 8 shorts, called the "tempTokenFields". + for (var i = 0; i < 8; i++) + { + reader.ReadInt16(); + } + + // Inventory token. + var tokenGUID = reader.ReadUInt32(); + var tokenFlags = reader.ReadUInt16(); + if (version > 0xCA) + { + var stackId = reader.ReadInt16(); + var personalInventoryInstanceId = reader.ReadInt32(); + var tokenCategory = reader.ReadUInt16(); + } + var numTokenProperties = reader.ReadUInt32(); + + for (var i = 0; i < numTokenProperties; i++) + { + reader.ReadUInt16(); + } + Debug.Log($"InventoryToken(tokenGUID={tokenGUID}, tokenFlags={tokenFlags}, numTokenProps={numTokenProperties})"); + + // Next is the number of object arrays. Each being a short array itself. + var numObjectArrays = reader.ReadInt16(); + var shortArrays = new List(numObjectArrays); + for (var i = 0; i < numObjectArrays; i++) + { + var objectArray = new short[reader.ReadInt16()]; + for (var j = 0; j < objectArray.Length; j++) + { + objectArray[j] = reader.ReadInt16(); + } + shortArrays.Add(objectArray); + } + Debug.Log($"numObjectArrays: {numObjectArrays}"); + + // An array of shorts. Unknown. + var numSecondShortArray = reader.ReadInt16(); + for (var i = 0; i < numSecondShortArray; i++) + { + reader.ReadInt16(); + } + Debug.Log($"numSecondShortArrays: {numSecondShortArray}"); + + var ownershipValue = reader.ReadInt32(); + Debug.Log($"ownershipValue: {ownershipValue}"); + + Debug.Log($" Position before strings: 0x{reader.Position:X}"); + // A number of material subsitution strings. + var materialSubstitutes = reader.ReadInt16(); + Debug.Log($" numMaterialSubstitues: {materialSubstitutes}"); + for (var i = 0; i < materialSubstitutes; i++) + { + var materialSubstitute = reader.ReadVariableLengthPascalString(); + Debug.Log($"materialSubstitute: {materialSubstitute}"); + } + + var persistentFlag = reader.ReadUInt16(); + Debug.Log($"persistentFlag: {persistentFlag}"); + + // Read the cTSTreeStack, a set of cTreeStackElems, probably the edith execution stack? + var numStackFrames = reader.ReadInt32(); + var frames = new SimsObjectStackFrame[numStackFrames]; + reader.ReadUInt32(); // unknown + for (var i = 0; i < numStackFrames; i++) + { + var objectID = reader.ReadUInt16(); + var treeID = reader.ReadUInt16(); + var nodeNum = reader.ReadUInt16(); + + var numLocals = reader.ReadByte(); + Debug.Log($"- numLocals: {numLocals}"); + + var numParams = reader.ReadByte(); + + var runningObjId = reader.ReadUInt16(); + var runningOnObjId = reader.ReadUInt16(); + + var frameParams = new short[numParams]; + for (var j = 0; j < frameParams.Length; j++) + { + frameParams[j] = reader.ReadInt16(); + } + + var locals = new short[numLocals]; + for (var j = 0; j < locals.Length; j++) + { + locals[j] = reader.ReadInt16(); + } + + var primState = reader.ReadInt32(); + + // next part is related to loading the cITSBehavior + var behavSaveType = reader.ReadUInt16(); + + Debug.Log($"- objectID: {objectID}, bhav: {behavSaveType}, runningObjID: {runningObjId}, runningOnObjID: {runningOnObjId}"); + Debug.Log($" locals: {string.Join(", ", locals)}"); + frames[i] = new SimsObjectStackFrame + { + ObjectId = objectID, + TreeId = treeID, + BhavSaveType = behavSaveType, + Locals = locals, + Params = frameParams + }; + } + + Debug.Log($"[P] Position before cTSRelationshipTable: 0x{reader.Position:X}"); + // Read the cTSRelationshipTable + var relationshipTableFlag = reader.ReadInt32(); + Debug.Log($" relationshipTableFlag: {relationshipTableFlag}"); + if (relationshipTableFlag < 0) + { + var relationShipCount = reader.ReadInt32(); + Debug.Log($" relationShipCount: {relationShipCount}"); + for (var i = 0; i < relationShipCount; i++) + { + var isPresent = reader.ReadInt32(); + if (isPresent == 0) + { + continue; + } + + var relationInstanceId = reader.ReadUInt32(); + + // TODO: read the entry here + var relationEntryCount = reader.ReadInt32(); + for (var j = 0; j < relationEntryCount; j++) + { + var entry = reader.ReadUInt32(); + } + } + } else if (relationshipTableFlag - 2 <= 1) + { + var relationShipCount = reader.ReadInt32(); + Debug.Log($" relationShipCount: {relationShipCount}"); + for (var i = 0; i < relationShipCount; i++) + { + var relationEntryId = reader.ReadUInt32(); + } + } + + // Slots... + var slotsFlag = reader.ReadInt16(); + Debug.Log($"slotsFlag: {slotsFlag}"); + if (slotsFlag < 0) + { + if (slotsFlag == -100) + { + // Unknown short. + reader.ReadUInt16(); + } + + var numSlots = reader.ReadInt16(); + for (var i = 0; i < numSlots; i++) + { + var slotValue = reader.ReadInt16(); + } + Debug.Log($"numSlots: {numSlots}"); + } + else + { + if (slotsFlag > 0) + { + // Two unknown shorts. + reader.ReadUInt16(); + reader.ReadUInt16(); + } + + for (var i = 0; i < slotsFlag - 1; i++) + { + // Two shorts per flag. + reader.ReadInt16(); + reader.ReadInt16(); + } + } + + Debug.Log($"Position before readEffects: 0x{reader.Position:X}"); + + var effectsFlag = reader.ReadInt16(); + Debug.Log($"effectsFlag: {effectsFlag}"); + if (effectsFlag != 0) + { + var hasEffects = reader.ReadUInt16() == 1; + Debug.Log($"hasEffects: {hasEffects}"); + if (hasEffects) + { + var effectCount = reader.ReadUInt32(); + for (var i = 0; i < effectCount; i++) + { + reader.ReadVariableLengthPascalString(); + reader.ReadVariableLengthPascalString(); + reader.ReadUInt32(); + reader.ReadUInt32(); + } + } + } + + var numbOverrides = reader.ReadInt16(); + Debug.Log($"numOverides: {numbOverrides}"); + + for (int i = 0; i < numbOverrides; i++) + { + var overrideString1 = reader.ReadVariableLengthPascalString(); + var overrideString2 = reader.ReadVariableLengthPascalString(); + var overrideString3 = reader.ReadVariableLengthPascalString(); + Debug.Log($"{overrideString1} / {overrideString2} / {overrideString3}"); + } + + return new SimsObjectAsset(tileLocationY: tileLocationY, tileLocationX: tileLocationX, level: level, + elevation: elevation, objectGroupId: objectGroupId, attrs: attrs, semiAttrs: semiAttrs, temp: temp, + data: data, + stackFrames: frames); + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/OpenTS2/Files/Formats/DBPF/SimsObjectCodec.cs.meta b/Assets/Scripts/OpenTS2/Files/Formats/DBPF/SimsObjectCodec.cs.meta new file mode 100644 index 00000000..45954160 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Files/Formats/DBPF/SimsObjectCodec.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 56e83332c7cd425b96ef041bca7ee9fc +timeCreated: 1727121939 \ No newline at end of file diff --git a/Assets/Scripts/OpenTS2/Files/Formats/Ini.meta b/Assets/Scripts/OpenTS2/Files/Formats/Ini.meta new file mode 100644 index 00000000..1985cd9e --- /dev/null +++ b/Assets/Scripts/OpenTS2/Files/Formats/Ini.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2afd7d55d98485345a0ccf234c508499 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Files/Formats/Ini/IniFile.cs b/Assets/Scripts/OpenTS2/Files/Formats/Ini/IniFile.cs new file mode 100644 index 00000000..772be000 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Files/Formats/Ini/IniFile.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OpenTS2.Files.Formats.Ini +{ + /// + /// Parses an .ini file. + /// + public class IniFile + { + public Dictionary Sections; + + public IniFile(string path) + { + Read(File.ReadAllBytes(path)); + } + + public Section GetSection(string name) + { + if (Sections.TryGetValue(name, out var section)) + return section; + return null; + } + + public string GetProperty(string sectionName, string propertyName, string defaultValue = "") + { + var section = GetSection(sectionName); + if (section == null) + return defaultValue; + if (section.KeyValues.TryGetValue(propertyName, out var val)) + return val; + return defaultValue; + } + + private void Read(byte[] data) + { + using var ms = new MemoryStream(data); + using var reader = new StreamReader(ms); + var sections = new Dictionary(); + Section currentSection = null; + string readLine; + while ((readLine = reader.ReadLine()) != null) + { + var line = readLine.Trim(); + if (string.IsNullOrEmpty(line)) continue; + if (line[0] == ';') continue; + if (line[0] == '[' && line[line.Length - 1] == ']') + { + currentSection = new Section(); + sections[line.Substring(1, line.Length - 2)] = currentSection; + continue; + } + if (currentSection == null) continue; + var split = line.Split('='); + var key = split[0].Trim(); + var value = split[1].Trim(); + currentSection.KeyValues[key] = value; + } + Sections = sections; + } + } +} diff --git a/Assets/Scripts/OpenTS2/Files/Formats/Ini/IniFile.cs.meta b/Assets/Scripts/OpenTS2/Files/Formats/Ini/IniFile.cs.meta new file mode 100644 index 00000000..32902929 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Files/Formats/Ini/IniFile.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 296c63a0e4f64be42800c90d526cf743 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Files/Formats/Ini/Section.cs b/Assets/Scripts/OpenTS2/Files/Formats/Ini/Section.cs new file mode 100644 index 00000000..5bf03493 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Files/Formats/Ini/Section.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OpenTS2.Files.Formats.Ini +{ + /// + /// INI Section with keys and values. + /// + public class Section + { + public Dictionary KeyValues = new Dictionary(); + } +} diff --git a/Assets/Scripts/OpenTS2/Files/Formats/Ini/Section.cs.meta b/Assets/Scripts/OpenTS2/Files/Formats/Ini/Section.cs.meta new file mode 100644 index 00000000..f9e1cf92 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Files/Formats/Ini/Section.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 85dc03b3d853bea48adf4c94accf1cdf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Files/Formats/SPX.meta b/Assets/Scripts/OpenTS2/Files/Formats/SPX.meta new file mode 100644 index 00000000..13a50425 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Files/Formats/SPX.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bc11afbd15a44ca409173ebe4736dc29 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Files/Formats/SPX/SPXFile.cs b/Assets/Scripts/OpenTS2/Files/Formats/SPX/SPXFile.cs new file mode 100644 index 00000000..0dd719ff --- /dev/null +++ b/Assets/Scripts/OpenTS2/Files/Formats/SPX/SPXFile.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml; +using NSpeex; + +namespace OpenTS2.Files.Formats.SPX +{ + public class SPXFile + { + public byte[] DecompressedData; + + public SPXFile(byte[] data) + { + Read(data); + } + + public void Read(byte[] data) + { + var ms = new MemoryStream(data); + var reader = new BinaryReader(ms); + //SPX1 + var magic = new string(reader.ReadChars(4)); + if (magic != "SPX1") + { + throw new IOException("Not a valid Speex file!"); + } + //always 1 + var channels = reader.ReadByte(); + var decodedSize = reader.ReadInt32(); + // (always 2, ultra-wideband mode, sampling rate 32khz) + var speexMode = reader.ReadInt32(); + // samples per frame/decoded frame size (640 samples, or 1280 bytes) + var samplesPerFrame = reader.ReadInt16(); + + var decoder = new SpeexDecoder((BandMode)speexMode, false); + var writer = new PcmWaveWriter(32000, 1); + var mw = new MemoryStream(); + writer.Open(mw); + writer.WriteHeader(""); + var shortArray = new short[samplesPerFrame]; + var byteArray = new byte[samplesPerFrame * 2]; + while (ms.Position < ms.Length) + { + var frameSize = reader.ReadByte(); + var frame = reader.ReadBytes(frameSize); + var decodeSize = decoder.Decode(frame, 0, frameSize, shortArray, 0, false); + Buffer.BlockCopy(shortArray, 0, byteArray, 0, decodeSize * 2); + writer.WritePacket(byteArray, 0, decodeSize * 2); + } + writer.Close(); + reader.Dispose(); + ms.Dispose(); + DecompressedData = mw.ToArray(); + mw.Dispose(); + } + } +} diff --git a/Assets/Scripts/OpenTS2/Files/Formats/SPX/SPXFile.cs.meta b/Assets/Scripts/OpenTS2/Files/Formats/SPX/SPXFile.cs.meta new file mode 100644 index 00000000..fa176c28 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Files/Formats/SPX/SPXFile.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2eadea47d57d5e549ae6c244423f74a7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Game/PluginSupport.cs b/Assets/Scripts/OpenTS2/Game/PluginSupport.cs index 7b94f213..236d522c 100644 --- a/Assets/Scripts/OpenTS2/Game/PluginSupport.cs +++ b/Assets/Scripts/OpenTS2/Game/PluginSupport.cs @@ -19,8 +19,8 @@ public static class PluginSupport /// public static void Initialize() { - var contentProvider = ContentProvider.Get(); - var assemblyAssets = contentProvider.GetAssetsOfType(TypeIDs.DLL); + var contentManager = ContentManager.Instance; + var assemblyAssets = contentManager.GetAssetsOfType(TypeIDs.DLL); var loadedAssemblies = new List(); foreach(var element in assemblyAssets) { diff --git a/Assets/Scripts/OpenTS2/Game/Simulator.cs b/Assets/Scripts/OpenTS2/Game/Simulator.cs index 416fff65..29bded52 100644 --- a/Assets/Scripts/OpenTS2/Game/Simulator.cs +++ b/Assets/Scripts/OpenTS2/Game/Simulator.cs @@ -12,24 +12,27 @@ namespace OpenTS2.Game { public class Simulator : MonoBehaviour { + public static Simulator Instance { get; private set; } public VM VirtualMachine => _virtualMachine; private VM _virtualMachine; public Context SimulationContext = Context.Neighborhood; + public bool DeleteEntityOnError = true; public enum Context { Lot = 1, Neighborhood = 2 } /// - /// Number of ticks to run per second. + /// Rate of simulator ticking, in seconds. /// - public int TickRate = 20; - private static Simulator _instance; + public float TickRate = 0.05f; + private float _timer = 0f; private void Awake() { - _instance = this; + Instance = this; _virtualMachine = new VM(); + _virtualMachine.ExceptionHandler += HandleException; } private void Start() @@ -37,20 +40,20 @@ private void Start() CreateGlobalObjects(); } - public Simulator Get() + private void Update() { - if (_instance != null) - return this; - return null; + _timer += Time.deltaTime; + var timesToTick = Mathf.FloorToInt(_timer / TickRate); + for (var i = 0; i < timesToTick; i++) + { + _virtualMachine.Tick(); + } + _timer -= timesToTick * TickRate; } private void CreateGlobalObjects() { - var objManager = ObjectManager.Get(); - if (objManager == null) - throw new NullReferenceException("Can't create global objects, Object Manager not constructed!"); - - var objects = objManager.Objects; + var objects = ObjectManager.Instance.Objects; foreach(var obj in objects) { @@ -64,20 +67,26 @@ private void CreateGlobalObjects() public VMEntity CreateObject(ObjectDefinitionAsset objectDefinition) { var entity = new VMEntity(objectDefinition); + _virtualMachine.AddEntity(entity); + try { - _virtualMachine.AddEntity(entity); - UpdateObjectData(entity); var initFunction = entity.ObjectDefinition.Functions.GetFunction(ObjectFunctionsAsset.FunctionNames.Init); if (initFunction.ActionTree != 0) entity.RunTreeImmediately(initFunction.ActionTree); + + var mainFunction = entity.ObjectDefinition.Functions.GetFunction(ObjectFunctionsAsset.FunctionNames.Main); + + if (mainFunction.ActionTree != 0) { + entity.PushTreeToThread(entity.MainThread, mainFunction.ActionTree); + } } - catch(SimAnticsException e) + catch(Exception e) { - HandleSimAnticsException(e); + HandleException(e, entity); } return entity; } @@ -88,9 +97,36 @@ void UpdateObjectData(VMEntity entity) entity.SetObjectData(VMObjectData.ObjectID, entity.ID); } + public void HandleException(Exception exception, VMEntity entity) + { + if (exception is SimAnticsException) + { + HandleSimAnticsException(exception as SimAnticsException); + return; + } + Debug.LogError($"Non-SimAntics exception caused by entity {entity.ID} - {entity.ObjectDefinition.FileName}\n{exception}"); + if (DeleteEntityOnError) + entity.Delete(); + } + public void HandleSimAnticsException(SimAnticsException exception) { Debug.LogError(exception.ToString()); + if (DeleteEntityOnError) + exception.StackFrame.Thread.Entity.Delete(); + } + + public void Kill() + { + Destroy(gameObject); + } + + public static Simulator Create(Context context) + { + var gameObject = new GameObject($"{context} Simulation"); + var simulator = gameObject.AddComponent(); + simulator.SimulationContext = context; + return simulator; } } } diff --git a/Assets/Scripts/OpenTS2/GameObjectExtensions.cs b/Assets/Scripts/OpenTS2/GameObjectExtensions.cs new file mode 100644 index 00000000..533b2f28 --- /dev/null +++ b/Assets/Scripts/OpenTS2/GameObjectExtensions.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace OpenTS2 +{ + public static class GameObjectExtensions + { + public static void SetLayerHierarchy(this GameObject go, int layer) + { + var transforms = go.GetComponentsInChildren(); + foreach(var transform in transforms) + { + transform.gameObject.layer = layer; + } + } + } +} diff --git a/Assets/Scripts/OpenTS2/GameObjectExtensions.cs.meta b/Assets/Scripts/OpenTS2/GameObjectExtensions.cs.meta new file mode 100644 index 00000000..3336ad55 --- /dev/null +++ b/Assets/Scripts/OpenTS2/GameObjectExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e0edf7d99923e6e4e8328a1727f8271f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/ListExtensions.cs b/Assets/Scripts/OpenTS2/ListExtensions.cs new file mode 100644 index 00000000..0354f8b4 --- /dev/null +++ b/Assets/Scripts/OpenTS2/ListExtensions.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OpenTS2 +{ + public static class ListExtensions + { + // https://stackoverflow.com/questions/273313/randomize-a-listt + + private static Random rng = new Random(); + + public static void Shuffle(this IList list) + { + int n = list.Count; + while (n > 1) + { + n--; + int k = rng.Next(n + 1); + T value = list[k]; + list[k] = list[n]; + list[n] = value; + } + } + } +} diff --git a/Assets/Scripts/OpenTS2/ListExtensions.cs.meta b/Assets/Scripts/OpenTS2/ListExtensions.cs.meta new file mode 100644 index 00000000..c0cc3c2f --- /dev/null +++ b/Assets/Scripts/OpenTS2/ListExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d4389cd1533048e46b2ce227c5083547 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Lua/API/ObjectAPI.cs b/Assets/Scripts/OpenTS2/Lua/API/ObjectAPI.cs index 7fc00c72..4ad19759 100644 --- a/Assets/Scripts/OpenTS2/Lua/API/ObjectAPI.cs +++ b/Assets/Scripts/OpenTS2/Lua/API/ObjectAPI.cs @@ -14,10 +14,7 @@ class GlobalObjManager { public bool isValidObjectGUID(uint guid) { - var objManager = ObjectManager.Get(); - if (objManager == null) - throw new ScriptRuntimeException("ObjectManager has not been constructed!"); - if (objManager.GetObjectByGUID(guid) != null) + if (ObjectManager.Instance.GetObjectByGUID(guid) != null) return true; return false; } @@ -26,10 +23,7 @@ public class ObjectAPI : LuaAPI { void SetObjectDefinitionField(uint guid, int field, ushort value) { - var objManager = ObjectManager.Get(); - if (objManager == null) - throw new ScriptRuntimeException("ObjectManager has not been constructed!"); - var obj = objManager.GetObjectByGUID(guid); + var obj = ObjectManager.Instance.GetObjectByGUID(guid); if (obj == null) throw new ScriptRuntimeException($"Object with GUID {guid} does not exist."); obj.Fields[field] = value; diff --git a/Assets/Scripts/OpenTS2/Lua/LuaManager.cs b/Assets/Scripts/OpenTS2/Lua/LuaManager.cs index 33ae5e25..1570450d 100644 --- a/Assets/Scripts/OpenTS2/Lua/LuaManager.cs +++ b/Assets/Scripts/OpenTS2/Lua/LuaManager.cs @@ -5,6 +5,7 @@ using System.Text; using System.Threading.Tasks; using MoonSharp.Interpreter; +using OpenTS2.Engine; using OpenTS2.Files; using OpenTS2.Files.Formats.DBPF; using OpenTS2.Lua.API; @@ -21,26 +22,21 @@ public class LuaManager /// /// Exit code of the current running Lua script called from SimAntics. /// - public VMExitCode ExitCode; + public VMExitCode ExitCode; /// /// SimAntics context of the current Lua script. /// public VMContext Context; - private static LuaManager _instance; + public static LuaManager Instance { get; private set; } private Script _script; private List _apis = new List(); private Dictionary _objectScriptsByName = new Dictionary(); - public static LuaManager Get() - { - return _instance; - } - public LuaManager() { - _instance = this; + Instance = this; _script = new Script(); var assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (var element in assemblies) @@ -48,6 +44,7 @@ public LuaManager() UserData.RegisterAssembly(element); } LoadAPIs(); + Core.OnFinishedLoading += InitializeObjectScripts; } void PrepGlobalsForPrimitive(short param0, short param1, short param2, VMContext ctx) @@ -68,7 +65,7 @@ void ThrowLuaPrimitiveException(ScriptRuntimeException exception, string name) /// public void InitializeObjectScripts() { - var objectScripts = Filesystem.GetLatestFilePath("Res/ObjectScripts/ObjectScripts.package"); + var objectScripts = Filesystem.GetLatestFilePath("TSData/Res/ObjectScripts/ObjectScripts.package"); if (objectScripts == null) { Debug.Log("LuaManager: No object scripts in current product."); diff --git a/Assets/Scripts/OpenTS2/NSpeex.meta b/Assets/Scripts/OpenTS2/NSpeex.meta new file mode 100644 index 00000000..ed2a76bd --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5fae5856b7f2bb948b21b1fb56f83538 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/NSpeex/AbsAudioWriter.cs b/Assets/Scripts/OpenTS2/NSpeex/AbsAudioWriter.cs new file mode 100644 index 00000000..e3cb65c7 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/AbsAudioWriter.cs @@ -0,0 +1,20 @@ +using System.IO; + +namespace NSpeex +{ + /// + /// abstract audio writer to file + /// + public abstract class AbsAudioWriter + { + + public abstract void Close(); + + public abstract void Open(string path); + + public abstract void WriteHeader(string comment); + + public abstract void WritePackage(byte[] data,int offset,int len); + + } +} diff --git a/Assets/Scripts/OpenTS2/NSpeex/AbsAudioWriter.cs.meta b/Assets/Scripts/OpenTS2/NSpeex/AbsAudioWriter.cs.meta new file mode 100644 index 00000000..2efaf642 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/AbsAudioWriter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 52a084a7e046f154bae10fd433615d9e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/NSpeex/AudioFileWriter.cs b/Assets/Scripts/OpenTS2/NSpeex/AudioFileWriter.cs new file mode 100644 index 00000000..76fb44c8 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/AudioFileWriter.cs @@ -0,0 +1,160 @@ +// +// Copyright (C) 2003 Jean-Marc Valin +// Copyright (C) 1999-2003 Wimba S.A., All Rights Reserved. +// Copyright (C) 2008 Filip Navara +// Copyright (C) 2009-2010 Christoph Frschl +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// - Neither the name of the Xiph.org Foundation nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +using System.IO; +using System; + +namespace NSpeex +{ + /// + /// Abstract Class that defines an Audio File Writer. + /// + public abstract class AudioFileWriter + { + /// + /// Closes the output file. + /// + /// + public abstract void Close(); + + /// + /// Open the output file. + /// + /// + public abstract void Open(Stream stream); + + /// + /// Open the output file. + /// + /// - + /// + public void Open(string filename) + { + Open(new FileStream(filename, FileMode.Create)); + } + + /// + /// Writes the header pages that start the Ogg Speex file. Prepares file for + /// data to be written. + /// + /// description to be included in the header. + /// + public abstract void WriteHeader(String comment); + + /// + /// Writes a packet of audio. + /// + /// audio data + /// the offset from which to start reading the data. + /// the length of data to read. + /// + public abstract void WritePacket(byte[] data, int offset, int len); + + /// + /// Writes a Speex Header to the given byte array. + /// + /// the buffer to write to. + /// the from which to start writing. + /// the amount of data written to the buffer. + protected static int WriteSpeexHeader( + BinaryWriter buf, + int sampleRate, + int mode, + int channels, + bool vbr, + int nframes) + { + buf.Write(System.Text.Encoding.UTF8.GetBytes("Speex ")); // 0 - 7: speex_string + buf.Write(System.Text.Encoding.UTF8.GetBytes("speex-1.0")); // 8 - 27: speex_version + for (int i = 0; i < 11; i++) + buf.Write(Byte.MinValue); // (fill in up to 20 bytes) + buf.Write(1); // 28 - 31: speex_version_id + buf.Write(80); // 32 - 35: header_size + buf.Write(sampleRate); // 36 - 39: rate + buf.Write(mode); // 40 - 43: mode (0=NB, 1=WB, 2=UWB) + buf.Write(4); // 44 - 47: mode_bitstream_version + buf.Write(channels); // 48 - 51: nb_channels + buf.Write(-1); // 52 - 55: bitrate + buf.Write(160 << mode); // 56 - 59: frame_size + // (NB=160, WB=320, UWB=640) + buf.Write((vbr) ? 1 : 0); // 60 - 63: vbr + buf.Write(nframes); // 64 - 67: frames_per_packet + buf.Write(0); // 68 - 71: extra_headers + buf.Write(0); // 72 - 75: reserved1 + buf.Write(0); // 76 - 79: reserved2 + return 80; + } + + /// + /// Builds a Speex Header. + /// + /// a Speex Header. + protected static byte[] BuildSpeexHeader( + int sampleRate, int mode, + int channels, bool vbr, int nframes) + { + byte[] data = new byte[80]; + WriteSpeexHeader(new BinaryWriter(new MemoryStream(data)), sampleRate, mode, channels, vbr, nframes); + return data; + } + + /// + /// Writes a Speex Comment to the given byte array. + /// + /// the buffer to write to. + /// the from which to start writing. + /// the comment. + /// the amount of data written to the buffer. + protected static int WriteSpeexComment(BinaryWriter buf, String comment) + { + int length = comment.Length; + buf.Write(length); // vendor comment size + buf.Write(System.Text.Encoding.UTF8.GetBytes(comment), 0, length); // vendor comment + buf.Write(0); // user comment list length + return length + 8; + } + + /// + /// Builds and returns a Speex Comment. + /// + /// the comment. + /// a Speex Comment. + protected static byte[] BuildSpeexComment(String comment) + { + byte[] data = new byte[comment.Length + 8]; + WriteSpeexComment(new BinaryWriter(new MemoryStream(data)), comment); + return data; + } + } +} diff --git a/Assets/Scripts/OpenTS2/NSpeex/AudioFileWriter.cs.meta b/Assets/Scripts/OpenTS2/NSpeex/AudioFileWriter.cs.meta new file mode 100644 index 00000000..cc13893a --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/AudioFileWriter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2b77aba3b2e2cc24c9e7f738e7037be4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/NSpeex/BandMode.cs b/Assets/Scripts/OpenTS2/NSpeex/BandMode.cs new file mode 100644 index 00000000..6320d124 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/BandMode.cs @@ -0,0 +1,57 @@ +// +// Copyright (C) 2003 Jean-Marc Valin +// Copyright (C) 1999-2003 Wimba S.A., All Rights Reserved. +// Copyright (C) 2008 Filip Navara +// Copyright (C) 2009-2010 Christoph Fröschl +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// - Neither the name of the Xiph.org Foundation nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +namespace NSpeex +{ + /// + /// Indicates the mode in which the encoder/decoder is working. + /// + public enum BandMode + { + /// + /// Narrow band. Is equal to 8kHz sample rate. + /// + Narrow = 0, + + /// + /// Wide band. Is equal to 16kHzs sample rate. + /// + Wide = 1, + + /// + /// Ultra-wide band. Is equal to 32kHz sample rate. + /// + UltraWide = 2 + } +} diff --git a/Assets/Scripts/OpenTS2/NSpeex/BandMode.cs.meta b/Assets/Scripts/OpenTS2/NSpeex/BandMode.cs.meta new file mode 100644 index 00000000..55ecba69 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/BandMode.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: dcbed706e0003ca4b8abeec4e679f609 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/NSpeex/BigEndian.cs b/Assets/Scripts/OpenTS2/NSpeex/BigEndian.cs new file mode 100644 index 00000000..517442d1 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/BigEndian.cs @@ -0,0 +1,177 @@ +using System; +using System.IO; +using System.Text; +namespace NSpeex +{ + /// + /// BigEndian + /// + public class BigEndian + { + + private static byte[] Convert(byte[] data) + { + if (BitConverter.IsLittleEndian) + { + // revert order + int size = data.Length; + byte[] result = new byte[size]; + for (int i = 0; i < data.Length; i++) + { + result[i] = data[size-1-i]; + } + return result; + + } + else + { + return data; + } + } + + public static void WriteShort(byte[] buf,int offset,short value) + { + // a short has 2 bytes + byte[] data = BitConverter.GetBytes(value); + byte[] data2 = Convert(data); + Array.Copy(data2, 0, buf, offset, 2); + } + + public static void WriteShort(Stream stream,short value) + { + // a short has 2 bytes + byte[] data = BitConverter.GetBytes(value); + byte[] data2 = Convert(data); + stream.Write(data2,0,data2.Length); + } + + + /// + /// write a int value to buf where index is offset, + /// that means from buf[offset] to buf[offset + 3] is value data + /// + public static void WriteInt(byte[] buf, int offset, int value) + { + byte[] data = BitConverter.GetBytes(value); + byte[] data2 = Convert(data); + Array.Copy(data2, 0, buf, offset, 4); + } + + public static void WriteInt(Stream stream, int value) + { + byte[] data = BitConverter.GetBytes(value); + byte[] data2 = Convert(data); + stream.Write(data2,0,data2.Length); + } + + + /// + /// write a long value to buf where index is offset, + /// that means from buf[offset] to buf[offset + 7] is value data + /// + public static void WriteLong(byte[] buf, int offset, long value) + { + byte[] data = BitConverter.GetBytes(value); + byte[] data2 = Convert(data); + Array.Copy(data2, 0, buf, offset, 8); + } + + public static void WriteLong(Stream stream, long value) + { + byte[] data = BitConverter.GetBytes(value); + byte[] data2 = Convert(data); + stream.Write(data2,0,data2.Length); + } + + /// + /// write a string value to buf where index is offset, + /// that means from buf[offset] to buf[offset + value.Length] is value data + /// + public static void WriteString(byte[] buf, int offset, string value) + { + byte[] data = UTF8Encoding.UTF8.GetBytes(value); + Array.Copy(data, 0, buf, offset, data.Length); + } + + public static void WriteString(Stream stram,string value) + { + byte[] data = UTF8Encoding.UTF8.GetBytes(value); + stram.Write(data,0,data.Length); + } + + public static short ReadShort(byte[] buf, int offset) + { + byte[] data = new byte[2] { 0, 0 }; + Array.Copy(buf, offset, data, 0, 2); + if (BitConverter.IsLittleEndian) + { + byte tmp = data[0]; + data[0] = data[1]; + data[1] = tmp; + } + return BitConverter.ToInt16(data, 0); + } + public static short ReadShort(Stream stream) + { + byte[] data = new byte[2] { 0, 0 }; + stream.Read(data, 0, 2); + byte[] data2 = Convert(data); + return BitConverter.ToInt16(data2, 0); + } + + + /// + /// read value from buf where index is offset + /// + public static int ReadInt(byte[] buf, int offset) + { + byte[] data = new byte[4] { 0, 0, 0, 0 }; + Array.Copy(buf, offset, data, 0, 4); + byte[] data2 = Convert(data); + return BitConverter.ToInt32(data2, 0); + } + public static int ReadInt(Stream stream) + { + byte[] data = new byte[4] { 0, 0, 0, 0 }; + stream.Read(data, 0, 4); + byte[] data2 = Convert(data); + return BitConverter.ToInt32(data2, 0); + } + + + /// + /// read value from buf where index is offset + /// + public static long ReadLong(byte[] buf, int offset) + { + byte[] data = new byte[8] { 0, 0, 0, 0, 0, 0, 0, 0 }; + Array.Copy(buf, offset, data, 0, 8); + byte[] data2 = Convert(data); + return BitConverter.ToInt64(data2, 0); + } + + public static long ReadLong(Stream stream) + { + byte[] data = new byte[8] { 0, 0, 0, 0, 0, 0, 0, 0 }; + stream.Read(data, 0, 8); + byte[] data2 = Convert(data); + return BitConverter.ToInt64(data2, 0); + } + + /// + /// read value from buf where index is offset and length is size + /// + public static string ReadString(byte[] buf, int offset, int size) + { + return UTF8Encoding.UTF8.GetString(buf, offset, size); + } + + public static string ReadString(Stream stream,int size) + { + byte[] data = new byte[size]; + stream.Read(data, 0, size); + return UTF8Encoding.UTF8.GetString(data, 0, size); + } + + } +} diff --git a/Assets/Scripts/OpenTS2/NSpeex/BigEndian.cs.meta b/Assets/Scripts/OpenTS2/NSpeex/BigEndian.cs.meta new file mode 100644 index 00000000..753cc187 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/BigEndian.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 32798b440a1792f47b793c95b833fad1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/NSpeex/Bits.cs b/Assets/Scripts/OpenTS2/NSpeex/Bits.cs new file mode 100644 index 00000000..af064dbf --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/Bits.cs @@ -0,0 +1,210 @@ +// +// Copyright (C) 2003 Jean-Marc Valin +// Copyright (C) 1999-2003 Wimba S.A., All Rights Reserved. +// Copyright (C) 2008 Filip Navara +// Copyright (C) 2009-2010 Christoph Frschl +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// - Neither the name of the Xiph.org Foundation nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +using System; + +namespace NSpeex +{ + /// + /// Speex bit packing and unpacking class. + /// + internal class Bits + { + /// + /// Default buffer size + /// + /// + public const int DefaultBufferSize = 1024; + + /// + /// "raw" data + /// + private byte[] bytes; + + /// + /// Position of the byte "cursor" + /// + private int bytePtr; + + /// + /// Position of the bit "cursor" within the current byte + /// + private int bitPtr; + + private int nbBits; + + /// + /// Initialise the bit packing variables. + /// + public Bits() + { + bytes = new byte[DefaultBufferSize]; + bytePtr = 0; + bitPtr = 0; + } + + /// + /// Advance n bits. + /// + public void Advance(int n) + { + bytePtr += n >> 3; + bitPtr += n & 7; + if (bitPtr > 7) + { + bitPtr -= 8; + bytePtr++; + } + } + + /// + /// Take a peek at the next bit. + /// + public int Peek() + { + return ((bytes[bytePtr] & 0xFF) >> (7 - bitPtr)) & 1; + } + + /// + /// Read the given array into the buffer. + /// + public void ReadFrom(byte[] newbytes, int offset, int len) + { + // resize if needed + if (bytes.Length < len) + bytes = new byte[len]; + + for (int i = 0; i < len; i++) + bytes[i] = newbytes[offset + i]; + bytePtr = 0; + bitPtr = 0; + nbBits = len*8; + } + + public int BitsRemaining() + { + return nbBits - (bytePtr*8 + bitPtr); + } + + /// + /// Read the next N bits from the buffer. + /// + /// the next N bits from the buffer. + public int Unpack(int nbBits) + { + int d = 0; + while (nbBits != 0) + { + d <<= 1; + d |= ((bytes[bytePtr] & 0xFF) >> (7 - bitPtr)) & 1; + bitPtr++; + if (bitPtr == 8) + { + bitPtr = 0; + bytePtr++; + } + nbBits--; + } + return d; + } + + /// + /// Write N bits of the given data to the buffer. + /// + public void Pack(int data, int nbBits) + { + int d = data; + + while (bytePtr + ((nbBits + bitPtr) >> 3) >= bytes.Length) + { + // Expand the buffer as needed. + int size = bytes.Length * 2; + byte[] tmp = new byte[size]; + Array.Copy(bytes, 0, tmp, 0, bytes.Length); + bytes = tmp; + } + while (nbBits > 0) + { + int bit; + bit = (d >> (nbBits - 1)) & 1; + bytes[bytePtr] |= (byte)(bit << (7 - bitPtr)); + bitPtr++; + if (bitPtr == 8) + { + bitPtr = 0; + bytePtr++; + } + nbBits--; + } + } + + public void InsertTerminator() + { + if (bitPtr > 0) + Pack(0, 1); + while (bitPtr != 0) + Pack(1, 1); + } + + public int Write(byte[] buffer, int offset, int maxBytes) + { + // insert terminator, but save the data so we can put it back after + var localBitPtr = bitPtr; + var localBytePtr = bytePtr; + var localBytes = bytes; + InsertTerminator(); + bitPtr = localBitPtr; + bytePtr = localBytePtr; + bytes = localBytes; + + if (maxBytes > BufferSize) + maxBytes = BufferSize; + + Array.Copy(bytes, 0, buffer, offset, maxBytes); + return maxBytes; + } + + public void Reset() + { + Array.Clear(bytes, 0, bytes.Length); + bytePtr = 0; + bitPtr = 0; + } + + public int BufferSize + { + get { return bytePtr + ((bitPtr > 0) ? 1 : 0); } + } + } +} diff --git a/Assets/Scripts/OpenTS2/NSpeex/Bits.cs.meta b/Assets/Scripts/OpenTS2/NSpeex/Bits.cs.meta new file mode 100644 index 00000000..4ddb768c --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/Bits.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2427093afcfe85e4ba3eb12d4a21424b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/NSpeex/CodebookSearch.cs b/Assets/Scripts/OpenTS2/NSpeex/CodebookSearch.cs new file mode 100644 index 00000000..8629665a --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/CodebookSearch.cs @@ -0,0 +1,74 @@ +// +// Copyright (C) 2003 Jean-Marc Valin +// Copyright (C) 1999-2003 Wimba S.A., All Rights Reserved. +// Copyright (C) 2008 Filip Navara +// Copyright (C) 2009-2010 Christoph Frschl +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// - Neither the name of the Xiph.org Foundation nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +#if FIXED_POINT +using SpeexWord16 = System.Int16; +using SpeexWord32 = System.Int32; +#else +using SpeexWord16 = System.Single; +using SpeexWord32 = System.Single; +#endif + +namespace NSpeex +{ + /// + /// Abstract class that is the base for the various Codebook search methods. + /// + internal abstract class CodebookSearch + { + /// + /// Codebook Search Quantification. + /// + /// target vector + /// LPCs for this subframe + /// Weighted LPCs for this subframe + /// Weighted LPCs for this subframe + /// number of LPC coeffs + /// number of samples in subframe + /// excitation array. + /// position in excitation array. + /// + /// Speex bits buffer. + /// + public abstract void Quantify( + SpeexWord16[] target, SpeexWord16[] ak, SpeexWord16[] awk1, + SpeexWord16[] awk2, int p, int nsf, SpeexWord32[] exc, int es, SpeexWord16[] r, + Bits bits, int complexity); + + /// + /// Codebook Search Unquantification. + /// + public abstract void Unquantify(SpeexWord32[] exc, int es, int nsf, Bits bits); + } +} diff --git a/Assets/Scripts/OpenTS2/NSpeex/CodebookSearch.cs.meta b/Assets/Scripts/OpenTS2/NSpeex/CodebookSearch.cs.meta new file mode 100644 index 00000000..9925d029 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/CodebookSearch.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f2c02d3bb5d61494cba471c5c24fa087 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/NSpeex/Codebook_Constants.cs b/Assets/Scripts/OpenTS2/NSpeex/Codebook_Constants.cs new file mode 100644 index 00000000..f05b61ad --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/Codebook_Constants.cs @@ -0,0 +1,761 @@ +// +// Copyright (C) 2003 Jean-Marc Valin +// Copyright (C) 1999-2003 Wimba S.A., All Rights Reserved. +// Copyright (C) 2008 Filip Navara +// Copyright (C) 2009-2010 Christoph Frschl +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// - Neither the name of the Xiph.org Foundation nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +namespace NSpeex +{ + internal class Codebook_Constants + { + /// + /// Excitation Codebook + /// + public static readonly int[] exc_20_32_table = + { + 12, 32, 25, 46, 36, 33, 9, + 14, -3, 6, 1, -8, 0, -10, -5, -7, -7, -7, -5, -5, 31, -27, 24, -32, + -4, 10, -11, 21, -3, 19, 23, -9, 22, 24, -10, -1, -10, -13, -7, + -11, 42, -33, 31, 19, -8, 0, -10, -16, 1, -21, -17, 10, -8, 14, 8, + 4, 11, -2, 5, -2, -33, 11, -16, 33, 11, -4, 9, -4, 11, 2, 6, -5, 8, + -5, 11, -4, -6, 26, -36, -16, 0, 4, -2, -8, 12, 6, -1, 34, -46, + -22, 9, 9, 21, 9, 5, -66, -5, 26, 2, 10, 13, 2, 19, 9, 12, -81, 3, + 13, 13, 0, -14, 22, -35, 6, -7, -4, 6, -6, 10, -6, -31, 38, -33, 0, + -10, -11, 5, -12, 12, -17, 5, 0, -6, 13, -9, 10, 8, 25, 33, 2, -12, + 8, -6, 10, -2, 21, 7, 17, 43, 5, 11, -7, -9, -20, -36, -20, -23, + -4, -4, -3, 27, -9, -9, -49, -39, -38, -11, -9, 6, 5, 23, 25, 5, 3, + 3, 4, 1, 2, -3, -1, 87, 39, 17, -21, -9, -19, -9, -15, -13, -14, + -17, -11, -10, -11, -8, -6, -1, -3, -3, -1, -54, -34, -27, -8, -11, + -4, -5, 0, 0, 4, 8, 6, 9, 7, 9, 7, 6, 5, 5, 5, 48, 10, 19, -10, 12, + -1, 9, -3, 2, 5, -3, 2, -2, -2, 0, -2, -26, 6, 9, -7, -16, -9, 2, + 7, 7, -5, -43, 11, 22, -11, -9, 34, 37, -15, -13, -6, 1, -1, 1, 1, + -64, 56, 52, -11, -27, 5, 4, 3, 1, 2, 1, 3, -1, -4, -4, -10, -7, + -4, -4, 2, -1, -7, -7, -12, -10, -15, -9, -5, -5, -11, -16, -13, 6, + 16, 4, -13, -16, -10, -4, 2, -47, -13, 25, 47, 19, -14, -20, -8, + -17, 0, -3, -13, 1, 6, -17, -14, 15, 1, 10, 6, -24, 0, -10, 19, + -69, -8, 14, 49, 17, -5, 33, -29, 3, -4, 0, 2, -8, 5, -6, 2, 120, + -56, -12, -47, 23, -9, 6, -5, 1, 2, -5, 1, -10, 4, -1, -1, 4, -1, + 0, -3, 30, -52, -67, 30, 22, 11, -1, -4, 3, 0, 7, 2, 0, 1, -10, -4, + -8, -13, 5, 1, 1, -1, 5, 13, -9, -3, -10, -62, 22, 48, -4, -6, 2, + 3, 5, 1, 1, 4, 1, 13, 3, -20, 10, -9, 13, -2, -4, 9, -20, 44, -1, + 20, -32, -67, 19, 0, 28, 11, 8, 2, -11, 15, -19, -53, 31, 2, 34, + 10, 6, -4, -58, 8, 10, 13, 14, 1, 12, 2, 0, 0, -128, 37, -8, 44, + -9, 26, -3, 18, 2, 6, 11, -1, 9, 1, 5, 3, 0, 1, 1, 2, 12, 3, -2, + -3, 7, 25, 9, 18, -6, -37, 3, -8, -16, 3, -10, -7, 17, -34, -44, + 11, 17, -15, -3, -16, -1, -13, 11, -46, -65, -2, 8, 13, 2, 4, 4, 5, + 15, 5, 9, 6, 8, 2, 8, 3, 10, -1, 3, -3, 6, -2, 3, 3, -5, 10, -11, + 7, 6, -2, 6, -2, -9, 19, -12, 12, -28, 38, 29, -1, 12, 2, 5, 23, + -10, 3, 4, -15, 21, -4, 3, 3, 6, 17, -9, -4, -8, -20, 26, 5, -10, + 6, 1, -19, 18, -15, -12, 47, -6, -2, -7, -9, -1, -17, -2, -2, -14, + 30, -14, 2, -7, -4, -1, -12, 11, -25, 16, -3, -12, 11, -7, 7, -17, + 1, 19, -28, 31, -7, -10, 7, -10, 3, 12, 5, -16, 6, 24, 41, -29, + -54, 0, 1, 7, -1, 5, -6, 13, 10, -4, -8, 8, -9, -27, -53, -38, -1, + 10, 19, 17, 16, 12, 12, 0, 3, -7, -4, 13, 12, -31, -14, 6, -5, 3, + 5, 17, 43, 50, 25, 10, 1, -6, -2 + }; + + /// + /// Excitation Codebook + /// + public static readonly int[] exc_10_16_table = + { + 22, 39, 14, 44, 11, 35, -2, + 23, -4, 6, 46, -28, 13, -27, -23, 12, 4, 20, -5, 9, 37, -18, -23, + 23, 0, 9, -6, -20, 4, -1, -17, -5, -4, 17, 0, 1, 9, -2, 1, 2, 2, + -12, 8, -25, 39, 15, 9, 16, -55, -11, 9, 11, 5, 10, -2, -60, 8, 13, + -6, 11, -16, 27, -47, -12, 11, 1, 16, -7, 9, -3, -29, 9, -14, 25, + -19, 34, 36, 12, 40, -10, -3, -24, -14, -37, -21, -35, -2, -36, 3, + -6, 67, 28, 6, -17, -3, -12, -16, -15, -17, -7, -59, -36, -13, 1, + 7, 1, 2, 10, 2, 11, 13, 10, 8, -2, 7, 3, 5, 4, 2, 2, -3, -8, 4, -5, + 6, 7, -42, 15, 35, -2, -46, 38, 28, -20, -9, 1, 7, -3, 0, -2, -5, + -4, -2, -4, -8, -3, -8, -5, -7, -4, -15, -28, 52, 32, 5, -5, -17, + -20, -10, -1 + }; + + /// + /// Excitation Codebook + /// + public static readonly int[] exc_10_32_table = + { + 7, 17, 17, 27, 25, 22, 12, 4, + -3, 0, 28, -36, 39, -24, -15, 3, -9, 15, -5, 10, 31, -28, 11, 31, + -21, 9, -11, -11, -2, -7, -25, 14, -22, 31, 4, -14, 19, -12, 14, + -5, 4, -7, 4, -5, 9, 0, -2, 42, -47, -16, 1, 8, 0, 9, 23, -57, 0, + 28, -11, 6, -31, 55, -45, 3, -5, 4, 2, -2, 4, -7, -3, 6, -2, 7, -3, + 12, 5, 8, 54, -10, 8, -7, -8, -24, -25, -27, -14, -5, 8, 5, 44, 23, + 5, -9, -11, -11, -13, -9, -12, -8, -29, -8, -22, 6, -15, 3, -12, + -1, -5, -3, 34, -1, 29, -16, 17, -4, 12, 2, 1, 4, -2, -4, 2, -1, + 11, -3, -52, 28, 30, -9, -32, 25, 44, -20, -24, 4, 6, -1, 0, 0, -3, + 7, -4, -4, -7, -6, -9, -2, -10, -7, -25, -10, 22, 29, 13, -13, -22, + -13, -4, 0, -4, -16, 10, 15, -36, -24, 28, 25, -1, -3, 66, -33, + -11, -15, 6, 0, 3, 4, -2, 5, 24, -20, -47, 29, 19, -2, -4, -1, 0, + -1, -2, 3, 1, 8, -11, 5, 5, -57, 28, 28, 0, -16, 4, -4, 12, -6, -1, + 2, -20, 61, -9, 24, -22, -42, 29, 6, 17, 8, 4, 2, -65, 15, 8, 10, + 5, 6, 5, 3, 2, -2, -3, 5, -9, 4, -5, 23, 13, 23, -3, -63, 3, -5, + -4, -6, 0, -3, 23, -36, -46, 9, 5, 5, 8, 4, 9, -5, 1, -3, 10, 1, + -6, 10, -11, 24, -47, 31, 22, -12, 14, -10, 6, 11, -7, -7, 7, -31, + 51, -12, -6, 7, 6, -17, 9, -11, -20, 52, -19, 3, -6, -6, -8, -5, + 23, -41, 37, 1, -21, 10, -14, 8, 7, 5, -15, -15, 23, 39, -26, -33, + 7, 2, -32, -30, -21, -8, 4, 12, 17, 15, 14, 11 + }; + + /// + /// Excitation Codebook + /// + public static readonly int[] exc_5_256_table = + { + -8, -37, 5, -43, 5, 73, 61, + 39, 12, -3, -61, -32, 2, 42, 30, -3, 17, -27, 9, 34, 20, -1, -5, 2, + 23, -7, -46, 26, 53, -47, 20, -2, -33, -89, -51, -64, 27, 11, 15, + -34, -5, -56, 25, -9, -1, -29, 1, 40, 67, -23, -16, 16, 33, 19, 7, + 14, 85, 22, -10, -10, -12, -7, -1, 52, 89, 29, 11, -20, -37, -46, + -15, 17, -24, -28, 24, 2, 1, 0, 23, -101, 23, 14, -1, -23, -18, 9, + 5, -13, 38, 1, -28, -28, 4, 27, 51, -26, 34, -40, 35, 47, 54, 38, + -54, -26, -6, 42, -25, 13, -30, -36, 18, 41, -4, -33, 23, -32, -7, + -4, 51, -3, 17, -52, 56, -47, 36, -2, -21, 36, 10, 8, -33, 31, 19, + 9, -5, -40, 10, -9, -21, 19, 18, -78, -18, -5, 0, -26, -36, -47, + -51, -44, 18, 40, 27, -2, 29, 49, -26, 2, 32, -54, 30, -73, 54, 3, + -5, 36, 22, 53, 10, -1, -84, -53, -29, -5, 3, -44, 53, -51, 4, 22, + 71, -35, -1, 33, -5, -27, -7, 36, 17, -23, -39, 16, -9, -55, -15, + -20, 39, -35, 6, -39, -14, 18, 48, -64, -17, -15, 9, 39, 81, 37, + -68, 37, 47, -21, -6, -104, 13, 6, 9, -2, 35, 8, -23, 18, 42, 45, + 21, 33, -5, -49, 9, -6, -43, -56, 39, 2, -16, -25, 87, 1, -3, -9, + 17, -25, -11, -9, -1, 10, 2, -14, -14, 4, -1, -10, 28, -23, 40, + -32, 26, -9, 26, 4, -27, -23, 3, 42, -60, 1, 49, -3, 27, 10, -52, + -40, -2, 18, 45, -23, 17, -44, 3, -3, 17, -46, 52, -40, -47, 25, + 75, 31, -49, 53, 30, -30, -32, -36, 38, -6, -15, -16, 54, -27, -48, + 3, 38, -29, -32, -22, -14, -4, -23, -13, 32, -39, 9, 8, -45, -13, + 34, -16, 49, 40, 32, 31, 28, 23, 23, 32, 47, 59, -68, 8, 62, 44, + 25, -14, -24, -65, -16, 36, 67, -25, -38, -21, 4, -33, -2, 42, 5, + -63, 40, 11, 26, -42, -23, -61, 79, -31, 23, -20, 10, -32, 53, -25, + -36, 10, -26, -5, 3, 0, -71, 5, -10, -37, 1, -24, 21, -54, -17, 1, + -29, -25, -15, -27, 32, 68, 45, -16, -37, -18, -5, 1, 0, -77, 71, + -6, 3, -20, 71, -67, 29, -35, 10, -30, 19, 4, 16, 17, 5, 0, -14, + 19, 2, 28, 26, 59, 3, 2, 24, 39, 55, -50, -45, -18, -17, 33, -35, + 14, -1, 1, 8, 87, -35, -29, 0, -27, 13, -7, 23, -13, 37, -40, 50, + -35, 14, 19, -7, -14, 49, 54, -5, 22, -2, -29, -8, -27, 38, 13, 27, + 48, 12, -41, -21, -15, 28, 7, -16, -24, -19, -20, 11, -20, 9, 2, + 13, 23, -20, 11, 27, -27, 71, -69, 8, 2, -6, 22, 12, 16, 16, 9, + -16, -8, -17, 1, 25, 1, 40, -37, -33, 66, 94, 53, 4, -22, -25, -41, + -42, 25, 35, -16, -15, 57, 31, -29, -32, 21, 16, -60, 45, 15, -1, + 7, 57, -26, -47, -29, 11, 8, 15, 19, -105, -8, 54, 27, 10, -17, 6, + -12, -1, -10, 4, 0, 23, -10, 31, 13, 11, 10, 12, -64, 23, -3, -8, + -19, 16, 52, 24, -40, 16, 10, 40, 5, 9, 0, -13, -7, -21, -8, -6, + -7, -21, 59, 16, -53, 18, -60, 11, -47, 14, -18, 25, -13, -24, 4, + -39, 16, -28, 54, 26, -67, 30, 27, -20, -52, 20, -12, 55, 12, 18, + -16, 39, -14, -6, -26, 56, -88, -55, 12, 25, 26, -37, 6, 75, 0, + -34, -81, 54, -30, 1, -7, 49, -23, -14, 21, 10, -62, -58, -57, -47, + -34, 15, -4, 34, -78, 31, 25, -11, 7, 50, -10, 42, -63, 14, -36, + -4, 57, 55, 57, 53, 42, -42, -1, 15, 40, 37, 15, 25, -11, 6, 1, 31, + -2, -6, -1, -7, -64, 34, 28, 30, -1, 3, 21, 0, -88, -12, -56, 25, + -28, 40, 8, -28, -14, 9, 12, 2, -6, -17, 22, 49, -6, -26, 14, 28, + -20, 4, -12, 50, 35, 40, 13, -38, -58, -29, 17, 30, 22, 60, 26, + -54, -39, -12, 58, -28, -63, 10, -21, -8, -12, 26, -62, 6, -10, + -11, -22, -6, -7, 4, 1, 18, 2, -70, 11, 14, 4, 13, 19, -24, -34, + 24, 67, 17, 51, -21, 13, 23, 54, -30, 48, 1, -13, 80, 26, -16, -2, + 13, -4, 6, -30, 29, -24, 73, -58, 30, -27, 20, -2, -21, 41, 45, 30, + -27, -3, -5, -18, -20, -49, -3, -35, 10, 42, -19, -67, -53, -11, 9, + 13, -15, -33, -51, -30, 15, 7, 25, -30, 4, 28, -22, -34, 54, -29, + 39, -46, 20, 16, 34, -4, 47, 75, 1, -44, -55, -24, 7, -1, 9, -42, + 50, -8, -36, 41, 68, 0, -4, -10, -23, -15, -50, 64, 36, -9, -27, + 12, 25, -38, -47, -37, 32, -49, 51, -36, 2, -4, 69, -26, 19, 7, 45, + 67, 46, 13, -63, 46, 15, -47, 4, -41, 13, -6, 5, -21, 37, 26, -55, + -7, 33, -1, -28, 10, -17, -64, -14, 0, -36, -17, 93, -3, -9, -66, + 44, -21, 3, -12, 38, -6, -13, -12, 19, 13, 43, -43, -10, -12, 6, + -5, 9, -49, 32, -5, 2, 4, 5, 15, -16, 10, -21, 8, -62, -8, 64, 8, + 79, -1, -66, -49, -18, 5, 40, -5, -30, -45, 1, -6, 21, -32, 93, + -18, -30, -21, 32, 21, -18, 22, 8, 5, -41, -54, 80, 22, -10, -7, + -8, -23, -64, 66, 56, -14, -30, -41, -46, -14, -29, -37, 27, -14, + 42, -2, -9, -29, 34, 14, 33, -14, 22, 4, 10, 26, 26, 28, 32, 23, + -72, -32, 3, 0, -14, 35, -42, -78, -32, 6, 29, -18, -45, -5, 7, + -33, -45, -3, -22, -34, 8, -8, 4, -51, -25, -9, 59, -78, 21, -5, + -25, -48, 66, -15, -17, -24, -49, -13, 25, -23, -64, -6, 40, -24, + -19, -11, 57, -33, -8, 1, 10, -52, -54, 28, 39, 49, 34, -11, -61, + -41, -43, 10, 15, -15, 51, 30, 15, -51, 32, -34, -2, -34, 14, 18, + 16, 1, 1, -3, -3, 1, 1, -18, 6, 16, 48, 12, -5, -42, 7, 36, 48, 7, + -20, -10, 7, 12, 2, 54, 39, -38, 37, 54, 4, -11, -8, -46, -10, 5, + -10, -34, 46, -12, 29, -37, 39, 36, -11, 24, 56, 17, 14, 20, 25, 0, + -25, -28, 55, -7, -5, 27, 3, 9, -26, -8, 6, -24, -10, -30, -31, + -34, 18, 4, 22, 21, 40, -1, -29, -37, -8, -21, 92, -29, 11, -3, 11, + 73, 23, 22, 7, 4, -44, -9, -11, 21, -13, 11, 9, -78, -1, 47, 114, + -12, -37, -19, -5, -11, -22, 19, 12, -30, 7, 38, 45, -21, -8, -9, + 55, -45, 56, -21, 7, 17, 46, -57, -87, -6, 27, 31, 31, 7, -56, -12, + 46, 21, -5, -12, 36, 3, 3, -21, 43, 19, 12, -7, 9, -14, 0, -9, -33, + -91, 7, 26, 3, -11, 64, 83, -31, -46, 25, 2, 9, 5, 2, 2, -1, 20, + -17, 10, -5, -27, -8, 20, 8, -19, 16, -21, -13, -31, 5, 5, 42, 24, + 9, 34, -20, 28, -61, 22, 11, -39, 64, -20, -1, -30, -9, -20, 24, + -25, -24, -29, 22, -60, 6, -5, 41, -9, -87, 14, 34, 15, -57, 52, + 69, 15, -3, -102, 58, 16, 3, 6, 60, -75, -32, 26, 7, -57, -27, -32, + -24, -21, -29, -16, 62, -46, 31, 30, -27, -15, 7, 15 + }; + + /// + /// Excitation Codebook + /// + public static readonly int[] exc_5_64_table = + { + 1, 5, -15, 49, -66, -48, -4, + 50, -44, 7, 37, 16, -18, 25, -26, -26, -15, 19, 19, -27, -47, 28, + 57, 5, -17, -32, -41, 68, 21, -2, 64, 56, 8, -16, -13, -26, -9, + -16, 11, 6, -39, 25, -19, 22, -31, 20, -45, 55, -43, 10, -16, 47, + -40, 40, -20, -51, 3, -17, -14, -15, -24, 53, -20, -46, 46, 27, + -68, 32, 3, -18, -5, 9, -31, 16, -9, -10, -1, -23, 48, 95, 47, 25, + -41, -32, -3, 15, -25, -55, 36, 41, -27, 20, 5, 13, 14, -22, 5, 2, + -23, 18, 46, -15, 17, -18, -34, -5, -8, 27, -55, 73, 16, 2, -1, + -17, 40, -78, 33, 0, 2, 19, 4, 53, -16, -15, -16, -28, -3, -13, 49, + 8, -7, -29, 27, -13, 32, 20, 32, -61, 16, 14, 41, 44, 40, 24, 20, + 7, 4, 48, -60, -77, 17, -6, -48, 65, -15, 32, -30, -71, -10, -3, + -6, 10, -2, -7, -29, -56, 67, -30, 7, -5, 86, -6, -10, 0, 5, -31, + 60, 34, -38, -3, 24, 10, -2, 30, 23, 24, -41, 12, 70, -43, 15, -17, + 6, 13, 16, -13, 8, 30, -15, -8, 5, 23, -34, -98, -4, -13, 13, -48, + -31, 70, 12, 31, 25, 24, -24, 26, -7, 33, -16, 8, 5, -11, -14, -8, + -65, 13, 10, -2, -9, 0, -3, -68, 5, 35, 7, 0, -31, -1, -17, -9, -9, + 16, -37, -18, -1, 69, -48, -28, 22, -21, -11, 5, 49, 55, 23, -86, + -36, 16, 2, 13, 63, -51, 30, -11, 13, 24, -18, -6, 14, -19, 1, 41, + 9, -5, 27, -36, -44, -34, -37, -21, -26, 31, -39, 15, 43, 5, -8, + 29, 20, -8, -20, -52, -28, -1, 13, 26, -34, -10, -9, 27, -8, 8, 27, + -66, 4, 12, -22, 49, 10, -77, 32, -18, 3, -38, 12, -3, -1, 2, 2, 0 + }; + + /// + /// Excitation Codebook + /// + public static readonly int[] exc_8_128_table = + { + -14, 9, 13, -32, 2, -10, 31, + -10, -8, -8, 6, -4, -1, 10, -64, 23, 6, 20, 13, 6, 8, -22, 16, 34, + 7, 42, -49, -28, 5, 26, 4, -15, 41, 34, 41, 32, 33, 24, 23, 14, 8, + 40, 34, 4, -24, -41, -19, -15, 13, -13, 33, -54, 24, 27, -44, 33, + 27, -15, -15, 24, -19, 14, -36, 14, -9, 24, -12, -4, 37, -5, 16, + -34, 5, 10, 33, -15, -54, -16, 12, 25, 12, 1, 2, 0, 3, -1, -4, -4, + 11, 2, -56, 54, 27, -20, 13, -6, -46, -41, -33, -11, -5, 7, 12, 14, + -14, -5, 8, 20, 6, 3, 4, -8, -5, -42, 11, 8, -14, 25, -2, 2, 13, + 11, -22, 39, -9, 9, 5, -45, -9, 7, -9, 12, -7, 34, -17, -102, 7, 2, + -42, 18, 35, -9, -34, 11, -5, -2, 3, 22, 46, -52, -25, -9, -94, 8, + 11, -5, -5, -5, 4, -7, -35, -7, 54, 5, -32, 3, 24, -9, -22, 8, 65, + 37, -1, -12, -23, -6, -9, -28, 55, -33, 14, -3, 2, 18, -60, 41, + -17, 8, -16, 17, -11, 0, -11, 29, -28, 37, 9, -53, 33, -14, -9, 7, + -25, -7, -11, 26, -32, -8, 24, -21, 22, -19, 19, -10, 29, -14, -10, + -4, -3, -2, 3, -1, -4, -4, -5, -52, 10, 41, 6, -30, -4, 16, 32, 22, + -27, -22, 32, -3, -28, -3, 3, -35, 6, 17, 23, 21, 8, 2, 4, -45, + -17, 14, 23, -4, -31, -11, -3, 14, 1, 19, -11, 2, 61, -8, 9, -12, + 7, -10, 12, -3, -24, 99, -48, 23, 50, -37, -5, -23, 0, 8, -14, 35, + -64, -5, 46, -25, 13, -1, -49, -19, -15, 9, 34, 50, 25, 11, -6, -9, + -16, -20, -32, -33, -32, -27, 10, -8, 12, -15, 56, -14, -32, 33, 3, + -9, 1, 65, -9, -9, -10, -2, -6, -23, 9, 17, 3, -28, 13, -32, 4, -2, + -10, 4, -16, 76, 12, -52, 6, 13, 33, -6, 4, -14, -9, -3, 1, -15, + -16, 28, 1, -15, 11, 16, 9, 4, -21, -37, -40, -6, 22, 12, -15, -23, + -14, -17, -16, -9, -10, -9, 13, -39, 41, 5, -9, 16, -38, 25, 46, + -47, 4, 49, -14, 17, -2, 6, 18, 5, -6, -33, -22, 44, 50, -2, 1, 3, + -6, 7, 7, -3, -21, 38, -18, 34, -14, -41, 60, -13, 6, 16, -24, 35, + 19, -13, -36, 24, 3, -17, -14, -10, 36, 44, -44, -29, -3, 3, -54, + -8, 12, 55, 26, 4, -2, -5, 2, -11, 22, -23, 2, 22, 1, -25, -39, 66, + -49, 21, -8, -2, 10, -14, -60, 25, 6, 10, 27, -25, 16, 5, -2, -9, + 26, -13, -20, 58, -2, 7, 52, -9, 2, 5, -4, -15, 23, -1, -38, 23, 8, + 27, -6, 0, -27, -7, 39, -10, -14, 26, 11, -45, -12, 9, -5, 34, 4, + -35, 10, 43, -22, -11, 56, -7, 20, 1, 10, 1, -26, 9, 94, 11, -27, + -14, -13, 1, -11, 0, 14, -5, -6, -10, -4, -15, -8, -41, 21, -5, 1, + -28, -8, 22, -9, 33, -23, -4, -4, -12, 39, 4, -7, 3, -60, 80, 8, + -17, 2, -6, 12, -5, 1, 9, 15, 27, 31, 30, 27, 23, 61, 47, 26, 10, + -5, -8, -12, -13, 5, -18, 25, -15, -4, -15, -11, 12, -2, -2, -16, + -2, -6, 24, 12, 11, -4, 9, 1, -9, 14, -45, 57, 12, 20, -35, 26, 11, + -64, 32, -10, -10, 42, -4, -9, -16, 32, 24, 7, 10, 52, -11, -57, + 29, 0, 8, 0, -6, 17, -17, -56, -40, 7, 20, 18, 12, -6, 16, 5, 7, + -1, 9, 1, 10, 29, 12, 16, 13, -2, 23, 7, 9, -3, -4, -5, 18, -64, + 13, 55, -25, 9, -9, 24, 14, -25, 15, -11, -40, -30, 37, 1, -19, 22, + -5, -31, 13, -2, 0, 7, -4, 16, -67, 12, 66, -36, 24, -8, 18, -15, + -23, 19, 0, -45, -7, 4, 3, -13, 13, 35, 5, 13, 33, 10, 27, 23, 0, + -7, -11, 43, -74, 36, -12, 2, 5, -8, 6, -33, 11, -16, -14, -5, -7, + -3, 17, -34, 27, -16, 11, -9, 15, 33, -31, 8, -16, 7, -6, -7, 63, + -55, -17, 11, -1, 20, -46, 34, -30, 6, 9, 19, 28, -9, 5, -24, -8, + -23, -2, 31, -19, -16, -5, -15, -18, 0, 26, 18, 37, -5, -15, -2, + 17, 5, -27, 21, -33, 44, 12, -27, -9, 17, 11, 25, -21, -31, -7, 13, + 33, -8, -25, -7, 7, -10, 4, -6, -9, 48, -82, -23, -8, 6, 11, -23, + 3, -3, 49, -29, 25, 31, 4, 14, 16, 9, -4, -18, 10, -26, 3, 5, -44, + -9, 9, -47, -55, 15, 9, 28, 1, 4, -3, 46, 6, -6, -38, -29, -31, + -15, -6, 3, 0, 14, -6, 8, -54, -50, 33, -5, 1, -14, 33, -48, 26, + -4, -5, -3, -5, -3, -5, -28, -22, 77, 55, -1, 2, 10, 10, -9, -14, + -66, -49, 11, -36, -6, -20, 10, -10, 16, 12, 4, -1, -16, 45, -44, + -50, 31, -2, 25, 42, 23, -32, -22, 0, 11, 20, -40, -35, -40, -36, + -32, -26, -21, -13, 52, -22, 6, -24, -20, 17, -5, -8, 36, -25, -11, + 21, -26, 6, 34, -8, 7, 20, -3, 5, -25, -8, 18, -5, -9, -4, 1, -9, + 20, 20, 39, 48, -24, 9, 5, -65, 22, 29, 4, 3, -43, -11, 32, -6, 9, + 19, -27, -10, -47, -14, 24, 10, -7, -36, -7, -1, -4, -5, -5, 16, + 53, 25, -26, -29, -4, -12, 45, -58, -34, 33, -5, 2, -1, 27, -48, + 31, -15, 22, -5, 4, 7, 7, -25, -3, 11, -22, 16, -12, 8, -3, 7, -11, + 45, 14, -73, -19, 56, -46, 24, -20, 28, -12, -2, -1, -36, -3, -33, + 19, -6, 7, 2, -15, 5, -31, -45, 8, 35, 13, 20, 0, -9, 48, -13, -43, + -3, -13, 2, -5, 72, -68, -27, 2, 1, -2, -7, 5, 36, 33, -40, -12, + -4, -5, 23, 19 + }; + + /// + /// Gain Codebook (narrowband) + /// + public static readonly int[] gain_cdbk_nb = + { // 384 + -32, -32, -32, -28, -67, -5, -42, -6, -32, -57, -10, -54, -16, 27, -41, 19, + -19, -40, -45, 24, -21, -8, -14, -18, 1, 14, -58, -18, -88, -39, + -38, 21, -18, -19, 20, -43, 10, 17, -48, -52, -58, -13, -44, -1, + -11, -12, -11, -34, 14, 0, -46, -37, -35, -34, -25, 44, -30, 6, -4, + -63, -31, 43, -41, -23, 30, -43, -43, 26, -14, -33, 1, -13, -13, + 18, -37, -46, -73, -45, -36, 24, -25, -36, -11, -20, -25, 12, -18, + -36, -69, -59, -45, 6, 8, -22, -14, -24, -1, 13, -44, -39, -48, + -26, -32, 31, -37, -33, 15, -46, -24, 30, -36, -41, 31, -23, -50, + 22, -4, -22, 2, -21, -17, 30, -34, -7, -60, -28, -38, 42, -28, -44, + -11, 21, -16, 8, -44, -39, -55, -43, -11, -35, 26, -9, 0, -34, -8, + 121, -81, 7, -16, -22, -37, 33, -31, -27, -7, -36, -34, 70, -57, + -37, -11, -48, -40, 17, -1, -33, 6, -6, -9, 0, -20, -21, 69, -33, + -29, 33, -31, -55, 12, -1, -33, 27, -22, -50, -33, -47, -50, 54, + 51, -1, -5, -44, -4, 22, -40, -39, -66, -25, -33, 1, -26, -24, -23, + -25, -11, 21, -45, -25, -45, -19, -43, 105, -16, 5, -21, 1, -16, + 11, -33, -13, -99, -4, -37, 33, -15, -25, 37, -63, -36, 24, -31, + -53, -56, -38, -41, -4, 4, -33, 13, -30, 49, 52, -94, -5, -30, -15, + 1, 38, -40, -23, 12, -36, -17, 40, -47, -37, -41, -39, -49, 34, 0, + -18, -7, -4, -16, 17, -27, 30, 5, -62, 4, 48, -68, -43, 11, -11, + -18, 19, -15, -23, -62, -39, -42, 10, -2, -21, -13, -13, -9, 13, + -47, -23, -62, -24, -44, 60, -21, -18, -3, -52, -22, 22, -36, -75, + 57, 16, -19, 3, 10, -29, 23, -38, -5, -62, -51, -51, 40, -18, -42, + 13, -24, -34, 14, -20, -56, -75, -26, -26, 32, 15, -26, 17, -29, + -7, 28, -52, -12, -30, 5, -5, -48, -5, 2, 2, -43, 21, 16, 16, -25, + -45, -32, -43, 18, -10, 9, 0, -1, -1, 7, -30, 19, -48, -4, -28, 25, + -29, -22, 0, -31, -32, 17, -10, -64, -41, -62, -52, 15, 16, -30, + -22, -32, -7, 9, -38 + }; + + /// + /// Gain Codebook (LBR) + /// + public static readonly int[] gain_cdbk_lbr = + { // 96 + -32, -32, -32, -31, -58, -16, -41, -24, -43, -56, -22, -55, -13, 33, -41, + -4, -39, -9, -41, 15, -12, -8, -15, -12, 1, 2, -44, -22, -66, -42, + -38, 28, -23, -21, 14, -37, 0, 21, -50, -53, -71, -27, -37, -1, + -19, -19, -5, -28, 6, 65, -44, -33, -48, -33, -40, 57, -14, -17, 4, + -45, -31, 38, -33, -23, 28, -40, -43, 29, -12, -34, 13, -23, -16, + 15, -27, -14, -82, -15, -31, 25, -32, -21, 5, -5, -47, -63, -51, + -46, 12, 3, -28, -17, -29, -10, 14, -40 + }; + + /// + /// Excitation Codebook + /// + public static readonly int[] hexc_10_32_table = + { + -3, -2, -1, 0, -4, 5, 35, + -40, -9, 13, -44, 5, -27, -1, -7, 6, -11, 7, -8, 7, 19, -14, 15, + -4, 9, -10, 10, -8, 10, -9, -1, 1, 0, 0, 2, 5, -18, 22, -53, 50, 1, + -23, 50, -36, 15, 3, -13, 14, -10, 6, 1, 5, -3, 4, -2, 5, -32, 25, + 5, -2, -1, -4, 1, 11, -29, 26, -6, -15, 30, -18, 0, 15, -17, 40, + -41, 3, 9, -2, -2, 3, -3, -1, -5, 2, 21, -6, -16, -21, 23, 2, 60, + 15, 16, -16, -9, 14, 9, -1, 7, -9, 0, 1, 1, 0, -1, -6, 17, -28, 54, + -45, -1, 1, -1, -6, -6, 2, 11, 26, -29, -2, 46, -21, 34, 12, -23, + 32, -23, 16, -10, 3, 66, 19, -20, 24, 7, 11, -3, 0, -3, -1, -50, + -46, 2, -18, -3, 4, -1, -2, 3, -3, -19, 41, -36, 9, 11, -24, 21, + -16, 9, -3, -25, -3, 10, 18, -9, -2, -5, -1, -5, 6, -4, -3, 2, -26, + 21, -19, 35, -15, 7, -13, 17, -19, 39, -43, 48, -31, 16, -9, 7, -2, + -5, 3, -4, 9, -19, 27, -55, 63, -35, 10, 26, -44, -2, 9, 4, 1, -6, + 8, -9, 5, -8, -1, -3, -16, 45, -42, 5, 15, -16, 10, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, -16, 24, -55, 47, -38, 27, -19, 7, -3, 1, 16, 27, + 20, -19, 18, 5, -7, 1, -5, 2, -6, 8, -22, 0, -3, -3, 8, -1, 7, -8, + 1, -3, 5, 0, 17, -48, 58, -52, 29, -7, -2, 3, -10, 6, -26, 58, -31, + 1, -6, 3, 93, -29, 39, 3, 17, 5, 6, -1, -1, -1, 27, 13, 10, 19, -7, + -34, 12, 10, -4, 9, -76, 9, 8, -28, -2, -11, 2, -1, 3, 1, -83, 38, + -39, 4, -16, -6, -2, -5, 5, -2 + }; + + /// + /// Excitation Codebook + /// + public static readonly int[] hexc_table = + { // 1024 + -24, 21, -20, 5, -5, -7, 14, -10, 2, -27, 16, -20, 0, -32, 26, 19, 8, -11, + -41, 31, 28, -27, -32, 34, 42, 34, -17, 22, -10, 13, -29, 18, -12, + -26, -24, 11, 22, 5, -5, -5, 54, -68, -43, 57, -25, 24, 4, 4, 26, + -8, -12, -17, 54, 30, -45, 1, 10, -15, 18, -41, 11, 68, -67, 37, + -16, -24, -16, 38, -22, 6, -29, 30, 66, -27, 5, 7, -16, 13, 2, -12, + -7, -3, -20, 36, 4, -28, 9, 3, 32, 48, 26, 39, 3, 0, 7, -21, -13, + 5, -82, -7, 73, -20, 34, -9, -5, 1, -1, 10, -5, -10, -1, 9, 1, -9, + 10, 0, -14, 11, -1, -2, -1, 11, 20, 96, -81, -22, -12, -9, -58, 9, + 24, -30, 26, -35, 27, -12, 13, -18, 56, -59, 15, -7, 23, -15, -1, + 6, -25, 14, -22, -20, 47, -11, 16, 2, 38, -23, -19, -30, -9, 40, + -11, 5, 4, -6, 8, 26, -21, -11, 127, 4, 1, 6, -9, 2, -7, -2, -3, 7, + -5, 10, -19, 7, -106, 91, -3, 9, -4, 21, -8, 26, -80, 8, 1, -2, + -10, -17, -17, -27, 32, 71, 6, -29, 11, -23, 54, -38, 29, -22, 39, + 87, -31, -12, -20, 3, -2, -2, 2, 20, 0, -1, -35, 27, 9, -6, -12, 3, + -12, -6, 13, 1, 14, -22, -59, -15, -17, -25, 13, -7, 7, 3, 0, 1, + -7, 6, -3, 61, -37, -23, -23, -29, 38, -31, 27, 1, -8, 2, -27, 23, + -26, 36, -34, 5, 24, -24, -6, 7, 3, -59, 78, -62, 44, -16, 1, 6, 0, + 17, 8, 45, 0, -110, 6, 14, -2, 32, -77, -56, 62, -3, 3, -13, 4, + -16, 102, -15, -36, -1, 9, -113, 6, 23, 0, 9, 9, 5, -8, -1, -14, 5, + -12, 121, -53, -27, -8, -9, 22, -13, 3, 2, -3, 1, -2, -71, 95, 38, + -19, 15, -16, -5, 71, 10, 2, -32, -13, -5, 15, -1, -2, -14, -85, + 30, 29, 6, 3, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, -65, -56, -9, 18, 18, + 23, -14, -2, 0, 12, -29, 26, -12, 1, 2, -12, -64, 90, -6, 4, 1, 5, + -5, -110, -3, -31, 22, -29, 9, 0, 8, -40, -5, 21, -5, -5, 13, 10, + -18, 40, 1, 35, -20, 30, -28, 11, -6, 19, 7, 14, 18, -64, 9, -6, + 16, 51, 68, 8, 16, 12, -8, 0, -9, 20, -22, 25, 7, -4, -13, 41, -35, + 93, -18, -54, 11, -1, 1, -9, 4, -66, 66, -31, 20, -22, 25, -23, 11, + 10, 9, 19, 15, 11, -5, -31, -10, -23, -28, -6, -6, -3, -4, 5, 3, + -28, 22, -11, -42, 25, -25, -16, 41, 34, 47, -6, 2, 42, -19, -22, + 5, -39, 32, 6, -35, 22, 17, -30, 8, -26, -11, -11, 3, -12, 33, 33, + -37, 21, -1, 6, -4, 3, 0, -5, 5, 12, -12, 57, 27, -61, -3, 20, -17, + 2, 0, 4, 0, -2, -33, -58, 81, -23, 39, -10, -5, 2, 6, -7, 5, 4, -3, + -2, -13, -23, -72, 107, 15, -5, 0, -7, -3, -6, 5, -4, 15, 47, 12, + -31, 25, -16, 8, 22, -25, -62, -56, -18, 14, 28, 12, 2, -11, 74, + -66, 41, -20, -7, 16, -20, 16, -8, 0, -16, 4, -19, 92, 12, -59, + -14, -39, 49, -25, -16, 23, -27, 19, -3, -33, 19, 85, -29, 6, -7, + -10, 16, -7, -12, 1, -6, 2, 4, -2, 64, 10, -25, 41, -2, -31, 15, 0, + 110, 50, 69, 35, 28, 19, -10, 2, -43, -49, -56, -15, -16, 10, 3, + 12, -1, -8, 1, 26, -12, -1, 7, -11, -27, 41, 25, 1, -11, -18, 22, + -7, -1, -47, -8, 23, -3, -17, -7, 18, -125, 59, -5, 3, 18, 1, 2, 3, + 27, -35, 65, -53, 50, -46, 37, -21, -28, 7, 14, -37, -5, -5, 12, 5, + -8, 78, -19, 21, -6, -16, 8, -7, 5, 2, 7, 2, 10, -6, 12, -60, 44, + 11, -36, -32, 31, 0, 2, -2, 2, 1, -3, 7, -10, 17, -21, 10, 6, -2, + 19, -2, 59, -38, -86, 38, 8, -41, -30, -45, -33, 7, 15, 28, 29, -7, + 24, -40, 7, 7, 5, -2, 9, 24, -23, -18, 6, -29, 30, 2, 28, 49, -11, + -46, 10, 43, -13, -9, -1, -3, -7, -7, -17, -6, 97, -33, -21, 3, 5, + 1, 12, -43, -8, 28, 7, -43, -7, 17, -20, 19, -1, 2, -13, 9, 54, 34, + 9, -28, -11, -9, -17, 110, -59, 44, -26, 0, 3, -12, -47, 73, -34, + -43, 38, -33, 16, -5, -46, -4, -6, -2, -25, 19, -29, 28, -13, 5, + 14, 27, -40, -43, 4, 32, -13, -2, -35, -4, 112, -42, 9, -12, 37, + -28, 17, 14, -19, 35, -39, 23, 3, -14, -1, -57, -5, 94, -9, 3, -39, + 5, 30, -10, -32, 42, -13, -14, -97, -63, 30, -9, 1, -7, 12, 5, 20, + 17, -9, -36, -30, 25, 47, -9, -15, 12, -22, 98, -8, -50, 15, -27, + 21, -16, -11, 2, 12, -10, 10, -3, 33, 36, -96, 0, -17, 31, -9, 9, + 3, -20, 13, -11, 8, -4, 10, -10, 9, 1, 112, -70, -27, 5, -21, 2, + -57, -3, -29, 10, 19, -21, 21, -10, -66, -3, 91, -35, 30, -12, 0, + -7, 59, -28, 26, 2, 14, -18, 1, 1, 11, 17, 20, -54, -59, 27, 4, 29, + 32, 5, 19, 12, -4, 1, 7, -10, 5, -2, 10, 0, 23, -5, 28, -104, 46, + 11, 16, 3, 29, 1, -8, -14, 1, 7, -50, 88, -62, 26, 8, -17, -14, 50, + 0, 32, -12, -3, -27, 18, -8, -5, 8, 3, -20, -11, 37, -12, 9, 33, + 46, -101, -1, -4, 1, 6, -1, 28, -42, -15, 16, 5, -1, -2, -55, 85, + 38, -9, -4, 11, -2, -9, -6, 3, -20, -10, -77, 89, 24, -3, -104, + -57, -26, -31, -20, -6, -9, 14, 20, -23, 46, -15, -31, 28, 1, -15, + -2, 6, -2, 31, 45, -76, 23, -25 + }; + + /// + /// LSP Codebook (high) + /// + public static readonly int[] high_lsp_cdbk = + { // 512 + 39, 12, -14, -20, -29, -61, -67, -76, -32, -71, -67, 68, 77, 46, 34, 5, + -13, -48, -46, -72, -81, -84, -60, -58, -40, -28, 82, 93, 68, 45, + 29, 3, -19, -47, -28, -43, -35, -30, -8, -13, -39, -91, -91, -123, + -96, 10, 10, -6, -18, -55, -60, -91, -56, -36, -27, -16, -48, -75, + 40, 28, -10, -28, 35, 9, 37, 19, 1, -20, -31, -41, -18, -25, -35, + -68, -80, 45, 27, -1, 47, 13, 0, -29, -35, -57, -50, -79, -73, -38, + -19, 5, 35, 14, -10, -23, 16, -8, 5, -24, -40, -62, -23, -27, -22, + -16, -18, -46, -72, -77, 43, 21, 33, 1, -80, -70, -70, -64, -56, + -52, -39, -33, -31, -38, -19, -19, -15, 32, 33, -2, 7, -15, -15, + -24, -23, -33, -41, -56, -24, -57, 5, 89, 64, 41, 27, 5, -9, -47, + -60, -97, -97, -124, -20, -9, -44, -73, 31, 29, -4, 64, 48, 7, -35, + -57, 0, -3, -26, -47, -3, -6, -40, -76, -79, -48, 12, 81, 55, 10, + 9, -24, -43, -73, -57, -69, 16, 5, -28, -53, 18, 29, 20, 0, -4, + -11, 6, -13, 23, 7, -17, -35, -37, -37, -30, -68, -63, 6, 24, -9, + -14, 3, 21, -13, -27, -57, -49, -80, -24, -41, -5, -16, -5, 1, 45, + 25, 12, -7, 3, -15, -6, -16, -15, -8, 6, -13, -42, -81, -80, -87, + 14, 1, -10, -3, -43, -69, -46, -24, -28, -29, 36, 6, -43, -56, -12, + 12, 54, 79, 43, 9, 54, 22, 2, 8, -12, -43, -46, -52, -38, -69, -89, + -5, 75, 38, 33, 5, -13, -53, -62, -87, -89, -113, -99, -55, -34, + -37, 62, 55, 33, 16, 21, -2, -17, -46, -29, -38, -38, -48, -39, + -42, -36, -75, -72, -88, -48, -30, 21, 2, -15, -57, -64, -98, -84, + -76, 25, 1, -46, -80, -12, 18, -7, 3, 34, 6, 38, 31, 23, 4, -1, 20, + 14, -15, -43, -78, -91, -24, 14, -3, 54, 16, 0, -27, -28, -44, -56, + -83, -92, -89, -3, 34, 56, 41, 36, 22, 20, -8, -7, -35, -42, -62, + -49, 3, 12, -10, -50, -87, -96, -66, 92, 70, 38, 9, -70, -71, -62, + -42, -39, -43, -11, -7, -50, -79, -58, -50, -31, 32, 31, -6, -4, + -25, 7, -17, -38, -70, -58, -27, -43, -83, -28, 59, 36, 20, 31, 2, + -27, -71, -80, -109, -98, -75, -33, -32, -31, -2, 33, 15, -6, 43, + 33, -5, 0, -22, -10, -27, -34, -49, -11, -20, -41, -91, -100, -121, + -39, 57, 41, 10, -19, -50, -38, -59, -60, -70, -18, -20, -8, -31, + -8, -15, 1, -14, -26, -25, 33, 21, 32, 17, 1, -19, -19, -26, -58, + -81, -35, -22, 45, 30, 11, -11, 3, -26, -48, -87, -67, -83, -58, 3, + -1, -26, -20, 44, 10, 25, 39, 5, -9, -35, -27, -38, 7, 10, 4, -9, + -42, -85, -102, -127, 52, 44, 28, 10, -47, -61, -40, -39, -17, -1, + -10, -33, -42, -74, -48, 21, -4, 70, 52, 10 + }; + + /// + /// LSP Codebook (high) + /// + public static readonly int[] high_lsp_cdbk2 = + { // 512 + -36, -62, 6, -9, -10, -14, -56, 23, 1, -26, 23, -48, -17, 12, 8, -7, 23, + 29, -36, -28, -6, -29, -17, -5, 40, 23, 10, 10, -46, -13, 36, 6, 4, + -30, -29, 62, 32, -32, -1, 22, -14, 1, -4, -22, -45, 2, 54, 4, -30, + -57, -59, -12, 27, -3, -31, 8, -9, 5, 10, -14, 32, 66, 19, 9, 2, + -25, -37, 23, -15, 18, -38, -31, 5, -9, -21, 15, 0, 22, 62, 30, 15, + -12, -14, -46, 77, 21, 33, 3, 34, 29, -19, 50, 2, 11, 9, -38, -12, + -37, 62, 1, -15, 54, 32, 6, 2, -24, 20, 35, -21, 2, 19, 24, -13, + 55, 4, 9, 39, -19, 30, -1, -21, 73, 54, 33, 8, 18, 3, 15, 6, -19, + -47, 6, -3, -48, -50, 1, 26, 20, 8, -23, -50, 65, -14, -55, -17, + -31, -37, -28, 53, -1, -17, -53, 1, 57, 11, -8, -25, -30, -37, 64, + 5, -52, -45, 15, 23, 31, 15, 14, -25, 24, 33, -2, -44, -56, -18, 6, + -21, -43, 4, -12, 17, -37, 20, -10, 34, 15, 2, 15, 55, 21, -11, + -31, -6, 46, 25, 16, -9, -25, -8, -62, 28, 17, 20, -32, -29, 26, + 30, 25, -19, 2, -16, -17, 26, -51, 2, 50, 42, 19, -66, 23, 29, -2, + 3, 19, -19, -37, 32, 15, 6, 30, -34, 13, 11, -5, 40, 31, 10, -42, + 4, -9, 26, -9, -70, 17, -2, -23, 20, -22, -55, 51, -24, -31, 22, + -22, 15, -13, 3, -10, -28, -16, 56, 4, -63, 11, -18, -15, -18, -38, + -35, 16, -7, 34, -1, -21, -49, -47, 9, -37, 7, 8, 69, 55, 20, 6, + -33, -45, -10, -9, 6, -9, 12, 71, 15, -3, -42, -7, -24, 32, -35, + -2, -42, -17, -5, 0, -2, -33, -54, 13, -12, -34, 47, 23, 19, 55, 7, + -8, 74, 31, 14, 16, -23, -26, 19, 12, -18, -49, -28, -31, -20, 2, + -14, -20, -47, 78, 40, 13, -23, -11, 21, -6, 18, 1, 47, 5, 38, 35, + 32, 46, 22, 8, 13, 16, -14, 18, 51, 19, 40, 39, 11, -26, -1, -17, + 47, 2, -53, -15, 31, -22, 38, 21, -15, -16, 5, -33, 53, 15, -38, + 86, 11, -3, -24, 49, 13, -4, -11, -18, 28, 20, -12, -27, -26, 35, + -25, -35, -3, -20, -61, 30, 10, -55, -12, -22, -52, -54, -14, 19, + -32, -12, 45, 15, -8, -48, -9, 11, -32, 8, -16, -34, -13, 51, 18, + 38, -2, -32, -17, 22, -2, -18, -28, -70, 59, 27, -28, -19, -10, + -20, -9, -9, -8, -21, 21, -8, 35, -2, 45, -3, -9, 12, 0, 30, 7, + -39, 43, 27, -38, -91, 30, 26, 19, -55, -4, 63, 14, -17, 13, 9, 13, + 2, 7, 4, 6, 61, 72, -1, -17, 29, -1, -22, -17, 8, -28, -37, 63, 44, + 41, 3, 2, 14, 9, -6, 75, -8, -7, -12, -15, -12, 13, 9, -4, 30, -22, + -65, 15, 0, -45, 4, -4, 1, 5, 22, 11, 23 + }; + + public const int NB_CDBK_SIZE = 64; + public const int NB_CDBK_SIZE_LOW1 = 64; + public const int NB_CDBK_SIZE_LOW2 = 64; + public const int NB_CDBK_SIZE_HIGH1 = 64; + public const int NB_CDBK_SIZE_HIGH2 = 64; + + /// + /// Codebook (narrowband) + /// + public static readonly int[] cdbk_nb = + { // 640 + 30, 19, 38, 34, 40, 32, 46, 43, 58, 43, 5, -18, -25, -40, -33, -55, -52, + 20, 34, 28, -20, -63, -97, -92, 61, 53, 47, 49, 53, 75, -14, -53, + -77, -79, 0, -3, -5, 19, 22, 26, -9, -53, -55, 66, 90, 72, 85, 68, + 74, 52, -4, -41, -58, -31, -18, -31, 27, 32, 30, 18, 24, 3, 8, 5, + -12, -3, 26, 28, 74, 63, -2, -39, -67, -77, -106, -74, 59, 59, 73, + 65, 44, 40, 71, 72, 82, 83, 98, 88, 89, 60, -6, -31, -47, -48, -13, + -39, -9, 7, 2, 79, -1, -39, -60, -17, 87, 81, 65, 50, 45, 19, -21, + -67, -91, -87, -41, -50, 7, 18, 39, 74, 10, -31, -28, 39, 24, 13, + 23, 5, 56, 45, 29, 10, -5, -13, -11, -35, -18, -8, -10, -8, -25, + -71, -77, -21, 2, 16, 50, 63, 87, 87, 5, -32, -40, -51, -68, 0, 12, + 6, 54, 34, 5, -12, 32, 52, 68, 64, 69, 59, 65, 45, 14, -16, -31, + -40, -65, -67, 41, 49, 47, 37, -11, -52, -75, -84, -4, 57, 48, 42, + 42, 33, -11, -51, -68, -6, 13, 0, 8, -8, 26, 32, -23, -53, 0, 36, + 56, 76, 97, 105, 111, 97, -1, -28, -39, -40, -43, -54, -44, -40, + -18, 35, 16, -20, -19, -28, -42, 29, 47, 38, 74, 45, 3, -29, -48, + -62, -80, -104, -33, 56, 59, 59, 10, 17, 46, 72, 84, 101, 117, 123, + 123, 106, -7, -33, -49, -51, -70, -67, -27, -31, 70, 67, -16, -62, + -85, -20, 82, 71, 86, 80, 85, 74, -19, -58, -75, -45, -29, -33, + -18, -25, 45, 57, -12, -42, -5, 12, 28, 36, 52, 64, 81, 82, 13, -9, + -27, -28, 22, 3, 2, 22, 26, 6, -6, -44, -51, 2, 15, 10, 48, 43, 49, + 34, -19, -62, -84, -89, -102, -24, 8, 17, 61, 68, 39, 24, 23, 19, + 16, -5, 12, 15, 27, 15, -8, -44, -49, -60, -18, -32, -28, 52, 54, + 62, -8, -48, -77, -70, 66, 101, 83, 63, 61, 37, -12, -50, -75, -64, + 33, 17, 13, 25, 15, 77, 1, -42, -29, 72, 64, 46, 49, 31, 61, 44, + -8, -47, -54, -46, -30, 19, 20, -1, -16, 0, 16, -12, -18, -9, -26, + -27, -10, -22, 53, 45, -10, -47, -75, -82, -105, -109, 8, 25, 49, + 77, 50, 65, 114, 117, 124, 118, 115, 96, 90, 61, -9, -45, -63, -60, + -75, -57, 8, 11, 20, 29, 0, -35, -49, -43, 40, 47, 35, 40, 55, 38, + -24, -76, -103, -112, -27, 3, 23, 34, 52, 75, 8, -29, -43, 12, 63, + 38, 35, 29, 24, 8, 25, 11, 1, -15, -18, -43, -7, 37, 40, 21, -20, + -56, -19, -19, -4, -2, 11, 29, 51, 63, -2, -44, -62, -75, -89, 30, + 57, 51, 74, 51, 50, 46, 68, 64, 65, 52, 63, 55, 65, 43, 18, -9, + -26, -35, -55, -69, 3, 6, 8, 17, -15, -61, -86, -97, 1, 86, 93, 74, + 78, 67, -1, -38, -66, -48, 48, 39, 29, 25, 17, -1, 13, 13, 29, 39, + 50, 51, 69, 82, 97, 98, -2, -36, -46, -27, -16, -30, -13, -4, -7, + -4, 25, -5, -11, -6, -25, -21, 33, 12, 31, 29, -8, -38, -52, -63, + -68, -89, -33, -1, 10, 74, -2, -15, 59, 91, 105, 105, 101, 87, 84, + 62, -7, -33, -50, -35, -54, -47, 25, 17, 82, 81, -13, -56, -83, 21, + 58, 31, 42, 25, 72, 65, -24, -66, -91, -56, 9, -2, 21, 10, 69, 75, + 2, -24, 11, 22, 25, 28, 38, 34, 48, 33, 7, -29, -26, 17, 15, -1, + 14, 0, -2, 0, -6, -41, -67, 6, -2, -9, 19, 2, 85, 74, -22, -67, + -84, -71, -50, 3, 11, -9, 2, 62 + }; + + /// + /// Codebook (narrowband) + /// + public static readonly int[] cdbk_nb_low1 = + { // 320 + -34, -52, -15, 45, 2, 23, 21, 52, 24, -33, -9, -1, 9, -44, -41, -13, -17, + 44, 22, -17, -6, -4, -1, 22, 38, 26, 16, 2, 50, 27, -35, -34, -9, + -41, 6, 0, -16, -34, 51, 8, -14, -31, -49, 15, -33, 45, 49, 33, + -11, -37, -62, -54, 45, 11, -5, -72, 11, -1, -12, -11, 24, 27, -11, + -43, 46, 43, 33, -12, -9, -1, 1, -4, -23, -57, -71, 11, 8, 16, 17, + -8, -20, -31, -41, 53, 48, -16, 3, 65, -24, -8, -23, -32, -37, -32, + -49, -10, -17, 6, 38, 5, -9, -17, -46, 8, 52, 3, 6, 45, 40, 39, -7, + -6, -34, -74, 31, 8, 1, -16, 43, 68, -11, -19, -31, 4, 6, 0, -6, + -17, -16, -38, -16, -30, 2, 9, -39, -16, -1, 43, -10, 48, 3, 3, + -16, -31, -3, 62, 68, 43, 13, 3, -10, 8, 20, -56, 12, 12, -2, -18, + 22, -15, -40, -36, 1, 7, 41, 0, 1, 46, -6, -62, -4, -12, -2, -11, + -83, -13, -2, 91, 33, -10, 0, 4, -11, -16, 79, 32, 37, 14, 9, 51, + -21, -28, -56, -34, 0, 21, 9, -26, 11, 28, -42, -54, -23, -2, -15, + 31, 30, 8, -39, -66, -39, -36, 31, -28, -40, -46, 35, 40, 22, 24, + 33, 48, 23, -34, 14, 40, 32, 17, 27, -3, 25, 26, -13, -61, -17, 11, + 4, 31, 60, -6, -26, -41, -64, 13, 16, -26, 54, 31, -11, -23, -9, + -11, -34, -71, -21, -34, -35, 55, 50, 29, -22, -27, -50, -38, 57, + 33, 42, 57, 48, 26, 11, 0, -49, -31, 26, -4, -14, 5, 78, 37, 17, 0, + -49, -12, -23, 26, 14, 2, 2, -43, -17, -12, 10, -8, -4, 8, 18, 12, + -6, 20, -12, -6, -13, -25, 34, 15, 40, 49, 7, 8, 13, 20, 20, -19, + -22, -2, -8, 2, 51, -51 + }; + + /// + /// Codebook (narrowband) + /// + public static readonly int[] cdbk_nb_low2 = + { // 320 + -6, 53, -21, -24, 4, 26, 17, -4, -37, 25, 17, -36, -13, 31, 3, -6, 27, 15, + -10, 31, 28, 26, -10, -10, -40, 16, -7, 15, 13, 41, -9, 0, -4, 50, + -6, -7, 14, 38, 22, 0, -48, 2, 1, -13, -19, 32, -3, -60, 11, -17, + -1, -24, -34, -1, 35, -5, -27, 28, 44, 13, 25, 15, 42, -11, 15, 51, + 35, -36, 20, 8, -4, -12, -29, 19, -47, 49, -15, -4, 16, -29, -39, + 14, -30, 4, 25, -9, -5, -51, -14, -3, -40, -32, 38, 5, -9, -8, -4, + -1, -22, 71, -3, 14, 26, -18, -22, 24, -41, -25, -24, 6, 23, 19, + -10, 39, -26, -27, 65, 45, 2, -7, -26, -8, 22, -12, 16, 15, 16, + -35, -5, 33, -21, -8, 0, 23, 33, 34, 6, 21, 36, 6, -7, -22, 8, -37, + -14, 31, 38, 11, -4, -3, -39, -32, -8, 32, -23, -6, -12, 16, 20, + -28, -4, 23, 13, -52, -1, 22, 6, -33, -40, -6, 4, -62, 13, 5, -26, + 35, 39, 11, 2, 57, -11, 9, -20, -28, -33, 52, -5, -6, -2, 22, -14, + -16, -48, 35, 1, -58, 20, 13, 33, -1, -74, 56, -18, -22, -31, 12, + 6, -14, 4, -2, -9, -47, 10, -3, 29, -17, -5, 61, 14, 47, -12, 2, + 72, -39, -17, 92, 64, -53, -51, -15, -30, -38, -41, -29, -28, 27, + 9, 36, 9, -35, -42, 81, -21, 20, 25, -16, -5, -17, -35, 21, 15, + -28, 48, 2, -2, 9, -19, 29, -40, 30, -18, -18, 18, -16, -57, 15, + -20, -12, -15, -37, -15, 33, -39, 21, -22, -13, 35, 11, 13, -38, + -63, 29, 23, -27, 32, 18, 3, -26, 42, 33, -64, -66, -17, 16, 56, 2, + 36, 3, 31, 21, -41, -39, 8, -57, 14, 37, -2, 19, -36, -19, -23, + -29, -16, 1, -3, -8, -10, 31, 64, -65 + }; + + /// + /// Codebook (narrowband) + /// + public static readonly int[] cdbk_nb_high1 = + { // 320 + -26, -8, 29, 21, 4, 19, -39, 33, -7, -36, 56, 54, 48, 40, 29, -4, -24, -42, + -66, -43, -60, 19, -2, 37, 41, -10, -37, -60, -64, 18, -22, 77, 73, + 40, 25, 4, 19, -19, -66, -2, 11, 5, 21, 14, 26, -25, -86, -4, 18, + 1, 26, -37, 10, 37, -1, 24, -12, -59, -11, 20, -6, 34, -16, -16, + 42, 19, -28, -51, 53, 32, 4, 10, 62, 21, -12, -34, 27, 4, -48, -48, + -50, -49, 31, -7, -21, -42, -25, -4, -43, -22, 59, 2, 27, 12, -9, + -6, -16, -8, -32, -58, -16, -29, -5, 41, 23, -30, -33, -46, -13, + -10, -38, 52, 52, 1, -17, -9, 10, 26, -25, -6, 33, -20, 53, 55, 25, + -32, -5, -42, 23, 21, 66, 5, -28, 20, 9, 75, 29, -7, -42, -39, 15, + 3, -23, 21, 6, 11, 1, -29, 14, 63, 10, 54, 26, -24, -51, -49, 7, + -23, -51, 15, -66, 1, 60, 25, 10, 0, -30, -4, -15, 17, 19, 59, 40, + 4, -5, 33, 6, -22, -58, -70, -5, 23, -6, 60, 44, -29, -16, -47, + -29, 52, -19, 50, 28, 16, 35, 31, 36, 0, -21, 6, 21, 27, 22, 42, 7, + -66, -40, -8, 7, 19, 46, 0, -4, 60, 36, 45, -7, -29, -6, -32, -39, + 2, 6, -9, 33, 20, -51, -34, 18, -6, 19, 6, 11, 5, -19, -29, -2, 42, + -11, -45, -21, -55, 57, 37, 2, -14, -67, -16, -27, -38, 69, 48, 19, + 2, -17, 20, -20, -16, -34, -17, -25, -61, 10, 73, 45, 16, -40, -64, + -17, -29, -22, 56, 17, -39, 8, -11, 8, -25, -18, -13, -19, 8, 54, + 57, 36, -17, -26, -4, 6, -21, 40, 42, -4, 20, 31, 53, 10, -34, -53, + 31, -17, 35, 0, 15, -6, -20, -63, -73, 22, 25, 29, 17, 8, -29, -39, + -69, 18, 15, -15, -5 + }; + + /// + /// Codebook (narrowband) + /// + public static readonly int[] cdbk_nb_high2 = + { // 320 + 11, 47, 16, -9, -46, -32, 26, -64, 34, -5, 38, -7, 47, 20, 2, -73, -99, -3, + -45, 20, 70, -52, 15, -6, -7, -82, 31, 21, 47, 51, 39, -3, 9, 0, + -41, -7, -15, -54, 2, 0, 27, -31, 9, -45, -22, -38, -24, -24, 8, + -33, 23, 5, 50, -36, -17, -18, -51, -2, 13, 19, 43, 12, -15, -12, + 61, 38, 38, 7, 13, 0, 6, -1, 3, 62, 9, 27, 22, -33, 38, -35, -9, + 30, -43, -9, -32, -1, 4, -4, 1, -5, -11, -8, 38, 31, 11, -10, -42, + -21, -37, 1, 43, 15, -13, -35, -19, -18, 15, 23, -26, 59, 1, -21, + 53, 8, -41, -50, -14, -28, 4, 21, 25, -28, -40, 5, -40, -41, 4, 51, + -33, -8, -8, 1, 17, -60, 12, 25, -41, 17, 34, 43, 19, 45, 7, -37, + 24, -15, 56, -2, 35, -10, 48, 4, -47, -2, 5, -5, -54, 5, -3, -33, + -10, 30, -2, -44, -24, -38, 9, -9, 42, 4, 6, -56, 44, -16, 9, -40, + -26, 18, -20, 10, 28, -41, -21, -4, 13, -18, 32, -30, -3, 37, 15, + 22, 28, 50, -40, 3, -29, -64, 7, 51, -19, -11, 17, -27, -40, -64, + 24, -12, -7, -27, 3, 37, 48, -1, 2, -9, -38, -34, 46, 1, 27, -6, + 19, -13, 26, 10, 34, 20, 25, 40, 50, -6, -7, 30, 9, -24, 0, -23, + 71, -61, 22, 58, -34, -4, 2, -49, -33, 25, 30, -8, -6, -16, 77, 2, + 38, -8, -35, -6, -30, 56, 78, 31, 33, -20, 13, -39, 20, 22, 4, 21, + -8, 4, -6, 10, -83, -41, 9, -25, -43, 15, -7, -12, -34, -39, -37, + -33, 19, 30, 16, -33, 42, -25, 25, -68, 44, -15, -11, -4, 23, 50, + 14, 4, -39, -43, 20, -30, 60, 9, -20, 7, 16, 19, -33, 37, 29, 16, + -35, 7, 38, -27 + }; + + /// + /// QMF (Quadratic Mirror Filter) table + /// + public static readonly float[] h0 = + { + 3.596189e-05f, -0.0001123515f, -0.0001104587f, 0.0002790277f, + 0.0002298438f, -0.0005953563f, -0.0003823631f, 0.00113826f, + 0.0005308539f, -0.001986177f, -0.0006243724f, 0.003235877f, + 0.0005743159f, -0.004989147f, -0.0002584767f, 0.007367171f, + -0.0004857935f, -0.01050689f, 0.001894714f, 0.01459396f, + -0.004313674f, -0.01994365f, 0.00828756f, 0.02716055f, + -0.01485397f, -0.03764973f, 0.026447f, 0.05543245f, + -0.05095487f, -0.09779096f, 0.1382363f, 0.4600981f, + 0.4600981f, 0.1382363f, -0.09779096f, -0.05095487f, + 0.05543245f, 0.026447f, -0.03764973f, -0.01485397f, + 0.02716055f, 0.00828756f, -0.01994365f, -0.004313674f, + 0.01459396f, 0.001894714f, -0.01050689f, -0.0004857935f, + 0.007367171f, -0.0002584767f, -0.004989147f, 0.0005743159f, + 0.003235877f, -0.0006243724f, -0.001986177f, 0.0005308539f, + 0.00113826f, -0.0003823631f, -0.0005953563f, 0.0002298438f, + 0.0002790277f, -0.0001104587f, -0.0001123515f, 3.596189e-05f + }; + + /// + /// QMF (Quadratic Mirror Filter) table + /// + public static readonly float[] h1 = + { + 3.596189e-05f, 0.0001123515f, -0.0001104587f, -0.0002790277f, + 0.0002298438f, 0.0005953563f, -0.0003823631f, -0.00113826f, + 0.0005308539f, 0.001986177f, -0.0006243724f, -0.003235877f, + 0.0005743159f, 0.004989147f, -0.0002584767f, -0.007367171f, + -0.0004857935f, 0.01050689f, 0.001894714f, -0.01459396f, + -0.004313674f, 0.01994365f, 0.00828756f, -0.02716055f, + -0.01485397f, 0.03764973f, 0.026447f, -0.05543245f, + -0.05095487f, 0.09779096f, 0.1382363f, -0.4600981f, + 0.4600981f, -0.1382363f, -0.09779096f, 0.05095487f, + 0.05543245f, -0.026447f, -0.03764973f, 0.01485397f, + 0.02716055f, -0.00828756f, -0.01994365f, 0.004313674f, + 0.01459396f, -0.001894714f, -0.01050689f, 0.0004857935f, + 0.007367171f, 0.0002584767f, -0.004989147f, -0.0005743159f, + 0.003235877f, 0.0006243724f, -0.001986177f, -0.0005308539f, + 0.00113826f, 0.0003823631f, -0.0005953563f, -0.0002298438f, + 0.0002790277f, 0.0001104587f, -0.0001123515f, -3.596189e-05f + }; + } +} diff --git a/Assets/Scripts/OpenTS2/NSpeex/Codebook_Constants.cs.meta b/Assets/Scripts/OpenTS2/NSpeex/Codebook_Constants.cs.meta new file mode 100644 index 00000000..28e287dd --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/Codebook_Constants.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bed0fd82aed2c3f499d3bc1e699c1de0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/NSpeex/Filters.cs b/Assets/Scripts/OpenTS2/NSpeex/Filters.cs new file mode 100644 index 00000000..93868d85 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/Filters.cs @@ -0,0 +1,337 @@ +// +// Copyright (C) 2003 Jean-Marc Valin +// Copyright (C) 1999-2003 Wimba S.A., All Rights Reserved. +// Copyright (C) 2008 Filip Navara +// Copyright (C) 2009-2010 Christoph Frschl +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// - Neither the name of the Xiph.org Foundation nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +using System; +#if FIXED_POINT +using SpeexWord16 = System.Int16; +using SpeexWord32 = System.Int32; +#else +using SpeexWord16 = System.Single; +using SpeexWord32 = System.Single; +#endif + +namespace NSpeex +{ + /// + /// Filters + /// + /// + /// @author Jim Lawrence, helloNetwork.com + /// @author Marc Gimpel, Wimba S.A. (mgimpel@horizonwimba.com) + /// @version $Revision: 1.2 $ + internal class Filters + { + private int last_pitch; + private float[] last_pitch_gain; + private float smooth_gain; + private float[] xx; + + public Filters() + { + last_pitch_gain = new float[3]; + xx = new float[1024]; + last_pitch = 0; + last_pitch_gain[0] = last_pitch_gain[1] = last_pitch_gain[2] = 0; + smooth_gain = 1; + } + + public static void Bw_lpc(float gamma, float[] lpc_in, + float[] lpc_out, int order) + { + float tmp = 1; + for (int i = 0; i < order + 1; i++) + { + lpc_out[i] = tmp * lpc_in[i]; + tmp *= gamma; + } + } + + public static void Filter_mem2(SpeexWord16[] x, int xs, + SpeexWord16[] num, SpeexWord16[] den, int N, int ord, + SpeexWord16[] mem, int ms) + { + int i, j; + SpeexWord16 xi, yi; + for (i = 0; i < N; i++) + { + xi = x[xs + i]; + x[xs + i] = (SpeexWord16)(num[0] * xi + mem[ms + 0]); + yi = x[xs + i]; + for (j = 0; j < ord - 1; j++) + { + mem[ms + j] = (SpeexWord16)(mem[ms + j + 1] + num[j + 1] * xi - den[j + 1] * yi); + } + mem[ms + ord - 1] = (SpeexWord16)(num[ord] * xi - den[ord] * yi); + } + } + + public static void Filter_mem2(SpeexWord16[] x, int xs, + SpeexWord16[] num, SpeexWord16[] den, SpeexWord16[] y, + int ys, int N, int ord, SpeexWord16[] mem, + int ms) + { + int i, j; + float xi, yi; + for (i = 0; i < N; i++) + { + xi = x[xs + i]; + y[ys + i] = (SpeexWord16)(num[0] * xi + mem[0]); + yi = y[ys + i]; + for (j = 0; j < ord - 1; j++) + { + mem[ms + j] = (SpeexWord16)(mem[ms + j + 1] + num[j + 1] * xi - den[j + 1] * yi); + } + mem[ms + ord - 1] = (SpeexWord16)(num[ord] * xi - den[ord] * yi); + } + } + + public static void Iir_mem2(SpeexWord16[] x, int xs, + SpeexWord16[] den, SpeexWord16[] y, int ys, int N, + int ord, SpeexWord16[] mem) + { + int i, j; + for (i = 0; i < N; i++) + { + y[ys + i] = (SpeexWord16)(x[xs + i] + mem[0]); + for (j = 0; j < ord - 1; j++) + { + mem[j] = (SpeexWord16)(mem[j + 1] - den[j + 1] * y[ys + i]); + } + mem[ord - 1] = (SpeexWord16)(-den[ord] * y[ys + i]); + } + } + + public static void Fir_mem2(float[] x, int xs, + float[] num, float[] y, int ys, int N, + int ord, float[] mem) + { + int i, j; + float xi; + for (i = 0; i < N; i++) + { + xi = x[xs + i]; + y[ys + i] = num[0] * xi + mem[0]; + for (j = 0; j < ord - 1; j++) + { + mem[j] = mem[j + 1] + num[j + 1] * xi; + } + mem[ord - 1] = num[ord] * xi; + } + } + + public static void Syn_percep_zero(SpeexWord16[] xx_0, int xxs, + SpeexWord16[] ak, SpeexWord16[] awk1, SpeexWord16[] awk2, + SpeexWord16[] y, int N, int ord) + { + int i; + SpeexWord16[] mem = new SpeexWord16[ord]; + // for (i=0;i + /// Comb Filter + /// + public void Comb_filter(float[] exc, int esi, + float[] new_exc, int nsi, int nsf, + int pitch, float[] pitch_gain, float comb_gain) + { + int i, j; + float exc_energy = 0.0f, new_exc_energy = 0.0f; + float gain, step, fact, g = 0.0f; + + /* Compute excitation energy prior to enhancement */ + for (i = esi; i < esi + nsf; i++) + { + exc_energy += exc[i] * exc[i]; + } + + /* Some gain adjustment if pitch is too high or if unvoiced */ + g = .5f * Math.Abs(pitch_gain[0] + pitch_gain[1] + + pitch_gain[2] + last_pitch_gain[0] + last_pitch_gain[1] + + last_pitch_gain[2]); + if (g > 1.3f) + comb_gain *= 1.3f / g; + if (g < .5f) + comb_gain *= 2.0f * g; + + step = 1.0f / nsf; + fact = 0; + + /* Apply pitch comb-filter (filter out noise between pitch harmonics) */ + for (i = 0, j = esi; i < nsf; i++, j++) + { + fact += step; + new_exc[nsi + i] = exc[j] + + comb_gain + * fact + * (pitch_gain[0] * exc[j - pitch + 1] + pitch_gain[1] + * exc[j - pitch] + pitch_gain[2] + * exc[j - pitch - 1]) + + comb_gain + * (1.0f - fact) + * (last_pitch_gain[0] * exc[j - last_pitch + 1] + + last_pitch_gain[1] * exc[j - last_pitch] + last_pitch_gain[2] + * exc[j - last_pitch - 1]); + } + + last_pitch_gain[0] = pitch_gain[0]; + last_pitch_gain[1] = pitch_gain[1]; + last_pitch_gain[2] = pitch_gain[2]; + last_pitch = pitch; + + /* Gain after enhancement */ + for (i = nsi; i < nsi + nsf; i++) + new_exc_energy += new_exc[i] * new_exc[i]; + + /* Compute scaling factor and normalize energy */ + gain = (float)(Math.Sqrt(exc_energy / (.1f + new_exc_energy))); + if (gain < .5f) + { + gain = .5f; + } + if (gain > 1.0f) + { + gain = 1.0f; + } + + for (i = nsi; i < nsi + nsf; i++) + { + smooth_gain = .96f * smooth_gain + .04f * gain; + new_exc[i] *= smooth_gain; + } + } + + /// + /// Quadrature Mirror Filter to Split the band in two. A 16kHz signal is thus + /// divided into two 8kHz signals representing the low and high bands. (used + /// by wideband encoder) + /// + public static void Qmf_decomp(float[] xx_0, float[] aa, + float[] y1, float[] y2, int N, int M, + float[] mem) + { + int i, j, k, M2; + float[] a; + float[] x; + int x2; + + a = new float[M]; + x = new float[N + M - 1]; + x2 = M - 1; + M2 = M >> 1; + for (i = 0; i < M; i++) + a[M - i - 1] = aa[i]; + for (i = 0; i < M - 1; i++) + x[i] = mem[M - i - 2]; + for (i = 0; i < N; i++) + x[i + M - 1] = xx_0[i]; + for (i = 0, k = 0; i < N; i += 2, k++) + { + y1[k] = 0; + y2[k] = 0; + for (j = 0; j < M2; j++) + { + y1[k] += a[j] * (x[i + j] + x[x2 + i - j]); + y2[k] -= a[j] * (x[i + j] - x[x2 + i - j]); + j++; + y1[k] += a[j] * (x[i + j] + x[x2 + i - j]); + y2[k] += a[j] * (x[i + j] - x[x2 + i - j]); + } + } + for (i = 0; i < M - 1; i++) + mem[i] = xx_0[N - i - 1]; + } + } +} diff --git a/Assets/Scripts/OpenTS2/NSpeex/Filters.cs.meta b/Assets/Scripts/OpenTS2/NSpeex/Filters.cs.meta new file mode 100644 index 00000000..65e2358d --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/Filters.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f1ff82357feb9d74f9f41a3c284e07c5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/NSpeex/HighLspQuant.cs b/Assets/Scripts/OpenTS2/NSpeex/HighLspQuant.cs new file mode 100644 index 00000000..670c8108 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/HighLspQuant.cs @@ -0,0 +1,89 @@ +// +// Copyright (C) 2003 Jean-Marc Valin +// Copyright (C) 1999-2003 Wimba S.A., All Rights Reserved. +// Copyright (C) 2008 Filip Navara +// Copyright (C) 2009-2010 Christoph Frschl +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// - Neither the name of the Xiph.org Foundation nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +using System; + +namespace NSpeex +{ + /// + /// LSP Quantisation and Unquantisation (high) + /// + internal class HighLspQuant : LspQuant + { + /// + /// Line Spectral Pair Quantification (high). + /// + public sealed override void Quant(float[] lsp, float[] qlsp, int order, Bits bits) + { + int i; + int id; + float[] quant_weight = new float[NSpeex.LspQuant.MAX_LSP_SIZE]; + + for (i = 0; i < order; i++) + qlsp[i] = lsp[i]; + quant_weight[0] = 1.0f / (qlsp[1] - qlsp[0]); + quant_weight[order - 1] = 1.0f / (qlsp[order - 1] - qlsp[order - 2]); + for (i = 1; i < order - 1; i++) + quant_weight[i] = Math.Max(1.0f / (qlsp[i] - qlsp[i - 1]), 1.0f / (qlsp[i + 1] - qlsp[i])); + + for (i = 0; i < order; i++) + qlsp[i] -= .3125f * i + .75f; + for (i = 0; i < order; i++) + qlsp[i] *= 256; + id = NSpeex.LspQuant.Lsp_quant(qlsp, 0, NSpeex.Codebook_Constants.high_lsp_cdbk, 64, order); + bits.Pack(id, 6); + + for (i = 0; i < order; i++) + qlsp[i] *= 2; + id = NSpeex.LspQuant.Lsp_weight_quant(qlsp, 0, quant_weight, 0, NSpeex.Codebook_Constants.high_lsp_cdbk2, 64, order); + bits.Pack(id, 6); + + for (i = 0; i < order; i++) + qlsp[i] *= 0.0019531f; + for (i = 0; i < order; i++) + qlsp[i] = lsp[i] - qlsp[i]; + } + + /// + /// Line Spectral Pair Unquantification (high). + /// + public sealed override void Unquant(float[] lsp, int order, Bits bits) + { + for (int i = 0; i < order; i++) + lsp[i] = .3125f * i + .75f; + UnpackPlus(lsp, NSpeex.Codebook_Constants.high_lsp_cdbk, bits, 0.0039062f, order, 0); + UnpackPlus(lsp, NSpeex.Codebook_Constants.high_lsp_cdbk2, bits, 0.0019531f, order, 0); + } + } +} diff --git a/Assets/Scripts/OpenTS2/NSpeex/HighLspQuant.cs.meta b/Assets/Scripts/OpenTS2/NSpeex/HighLspQuant.cs.meta new file mode 100644 index 00000000..fef7a4dd --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/HighLspQuant.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3cf5758e9f6c4984bb4726678af68a0e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/NSpeex/IDecoder.cs b/Assets/Scripts/OpenTS2/NSpeex/IDecoder.cs new file mode 100644 index 00000000..2149189c --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/IDecoder.cs @@ -0,0 +1,86 @@ +// +// Copyright (C) 2003 Jean-Marc Valin +// Copyright (C) 1999-2003 Wimba S.A., All Rights Reserved. +// Copyright (C) 2008 Filip Navara +// Copyright (C) 2009-2010 Christoph Frschl +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// - Neither the name of the Xiph.org Foundation nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +namespace NSpeex +{ + /// + /// Speex Decoder inteface, used as a base for the Narrowband and sideband + /// decoders. + /// + internal interface IDecoder + { + /// + /// Decode the given input bits. + /// + /// 1 if a terminator was found, 0 if not. + /// If there is an error detected in the data stream. + int Decode(Bits bits, float[] xout); + + /// + /// Decode the given bits to stereo. + /// + void DecodeStereo(float[] data, int frameSize); + + bool PerceptualEnhancement + { + get; + set; + } + + int FrameSize + { + get; + } + + bool Dtx + { + get; + } + + float[] PiGain + { + get; + } + + float[] Exc + { + get; + } + + float[] Innov + { + get; + } + } +} diff --git a/Assets/Scripts/OpenTS2/NSpeex/IDecoder.cs.meta b/Assets/Scripts/OpenTS2/NSpeex/IDecoder.cs.meta new file mode 100644 index 00000000..9812bda5 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/IDecoder.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 397254651241e4e46a602a3916a2761d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/NSpeex/IEncoder.cs b/Assets/Scripts/OpenTS2/NSpeex/IEncoder.cs new file mode 100644 index 00000000..b783f211 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/IEncoder.cs @@ -0,0 +1,143 @@ +// +// Copyright (C) 2003 Jean-Marc Valin +// Copyright (C) 1999-2003 Wimba S.A., All Rights Reserved. +// Copyright (C) 2008 Filip Navara +// Copyright (C) 2009-2010 Christoph Frschl +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// - Neither the name of the Xiph.org Foundation nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +namespace NSpeex +{ + /// + /// Speex Encoder interface, used as a base for the Narrowband and sideband + /// encoders. + /// + internal interface IEncoder + { + /// + /// Encode the given input signal. + /// + /// 1 if successful. + int Encode(Bits bits, float[] ins0); + + int EncodedFrameSize + { + get; + } + + int FrameSize + { + get; + } + + int Quality + { + set; + } + + int BitRate + { + get; + set; + } + + float[] PiGain + { + get; + } + + float[] Exc + { + get; + } + + float[] Innov + { + get; + } + + int Mode + { + get; + set; + } + + bool Vbr + { + get; + set; + } + + bool Vad + { + get; + set; + } + + bool Dtx + { + get; + set; + } + + int Abr + { + get; + set; + } + + float VbrQuality + { + get; + set; + } + + int Complexity + { + get; + set; + } + + int SamplingRate + { + get; + set; + } + + int LookAhead + { + get; + } + + float RelativeQuality + { + get; + } + } +} diff --git a/Assets/Scripts/OpenTS2/NSpeex/IEncoder.cs.meta b/Assets/Scripts/OpenTS2/NSpeex/IEncoder.cs.meta new file mode 100644 index 00000000..de12fd5d --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/IEncoder.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 88815b76818c5b241bab9b8c9f6882af +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/NSpeex/Inband.cs b/Assets/Scripts/OpenTS2/NSpeex/Inband.cs new file mode 100644 index 00000000..3c59075d --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/Inband.cs @@ -0,0 +1,123 @@ +// +// Copyright (C) 2003 Jean-Marc Valin +// Copyright (C) 1999-2003 Wimba S.A., All Rights Reserved. +// Copyright (C) 2008 Filip Navara +// Copyright (C) 2009-2010 Christoph Frschl +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// - Neither the name of the Xiph.org Foundation nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +namespace NSpeex +{ + /// + /// Speex in-band and User in-band controls. + /// + internal class Inband + { + private Stereo stereo; + + public Inband(Stereo stereo) + { + this.stereo = stereo; + } + + /// + /// Speex in-band request (submode=14). + /// + public void SpeexInbandRequest(Bits bits) + { + int code = bits.Unpack(4); + switch (code) + { + case 0: // asks the decoder to set perceptual enhancment off (0) or on + // (1) + bits.Advance(1); + break; + case 1: // asks (if 1) the encoder to be less "aggressive" due to high + // packet loss + bits.Advance(1); + break; + case 2: // asks the encoder to switch to mode N + bits.Advance(4); + break; + case 3: // asks the encoder to switch to mode N for low-band + bits.Advance(4); + break; + case 4: // asks the encoder to switch to mode N for high-band + bits.Advance(4); + break; + case 5: // asks the encoder to switch to quality N for VBR + bits.Advance(4); + break; + case 6: // request acknowledgement (0=no, 1=all, 2=only for inband data) + bits.Advance(4); + break; + case 7: // asks the encoder to set CBR(0), VAD(1), DTX(3), VBR(5), + // VBR+DTX(7) + bits.Advance(4); + break; + case 8: // transmit (8-bit) character to the other end + bits.Advance(8); + break; + case 9: // intensity stereo information + // setup the stereo decoder; to skip: tmp = bits.unpack(8); break; + stereo.Init(bits); // read 8 bits + break; + case 10: // announce maximum bit-rate acceptable (N in byets/second) + bits.Advance(16); + break; + case 11: // reserved + bits.Advance(16); + break; + case 12: // Acknowledge receiving packet N + bits.Advance(32); + break; + case 13: // reserved + bits.Advance(32); + break; + case 14: // reserved + bits.Advance(64); + break; + case 15: // reserved + bits.Advance(64); + break; + default: + break; + } + } + + /// + /// User in-band request (submode=13). + /// + public void UserInbandRequest(Bits bits) + { + int req_size = bits.Unpack(4); + bits.Advance(5 + 8 * req_size); + } + } +} diff --git a/Assets/Scripts/OpenTS2/NSpeex/Inband.cs.meta b/Assets/Scripts/OpenTS2/NSpeex/Inband.cs.meta new file mode 100644 index 00000000..4d71a73f --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/Inband.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 04123d935eb3e07439b3d8c17850055f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/NSpeex/InvalidFormatException.cs b/Assets/Scripts/OpenTS2/NSpeex/InvalidFormatException.cs new file mode 100644 index 00000000..61eabf15 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/InvalidFormatException.cs @@ -0,0 +1,48 @@ +// +// Copyright (C) 2009-2010 Christoph Fröschl +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// - Neither the name of the Xiph.org Foundation nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +using System; + +namespace NSpeex +{ + /// + /// Indicates a mal-formed speex stream. + /// + public class InvalidFormatException : Exception + { + /// + /// Creates a new instance. + /// + /// + public InvalidFormatException(string message) : base(message) + {} + } +} diff --git a/Assets/Scripts/OpenTS2/NSpeex/InvalidFormatException.cs.meta b/Assets/Scripts/OpenTS2/NSpeex/InvalidFormatException.cs.meta new file mode 100644 index 00000000..39e298c8 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/InvalidFormatException.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 43a0351794a82a84093f2c225af72407 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/NSpeex/JitterBuffer.cs b/Assets/Scripts/OpenTS2/NSpeex/JitterBuffer.cs new file mode 100644 index 00000000..f9000cb3 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/JitterBuffer.cs @@ -0,0 +1,951 @@ +// +// Copyright (C) 2003 Jean-Marc Valin +// Copyright (C) 2009-2010 Christoph Fröschl +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// - Neither the name of the Xiph.org Foundation nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +using System.Diagnostics; +using System; + +namespace NSpeex +{ + /// + /// Jitter buffer implemenation. + /// + public class JitterBuffer + { + private static int RoundDown(int x, int step) + { + if (x < 0) + { + return (x - step + 1) / step * step; + } + else + { + return x / step * step; + } + } + + private const int MAX_BUFFER_SIZE = 200; + private const int MAX_TIMINGS = 40; + private const int MAX_BUFFERS = 3; + private const int TOP_DELAY = 40; + + class TimingBuffer + { + public int filled; + public int curr_count; + public int[] timing = new int[MAX_TIMINGS]; + public short[] counts = new short[MAX_TIMINGS]; + + internal void Init() + { + filled = 0; + curr_count = 0; + } + + internal void Add(short timing) + { + int pos; + /* Discard packet that won't make it into the list because they're too early */ + if (filled >= MAX_TIMINGS && timing >= this.timing[filled - 1]) + { + curr_count++; + return; + } + + /* Find where the timing info goes in the sorted list */ + pos = 0; + /* FIXME: Do bisection instead of linear search */ + while (pos < filled && timing >= this.timing[pos]) + { + pos++; + } + + Debug.Assert(pos <= filled && pos < MAX_TIMINGS); + + /* Shift everything so we can perform the insertion */ + if (pos < filled) + { + int move_size = filled - pos; + if (filled == MAX_TIMINGS) + move_size -= 1; + + Array.Copy(this.timing, pos, this.timing, pos + 1, move_size); + //SPEEX_MOVE(&tb->timing[pos + 1], &tb->timing[pos], move_size); + Array.Copy(counts, pos, counts, pos + 1, move_size); + //SPEEX_MOVE(&tb->counts[pos + 1], &tb->counts[pos], move_size); + } + /* Insert */ + this.timing[pos] = timing; + counts[pos] = (short)curr_count; + + curr_count++; + if (filled < MAX_TIMINGS) + filled++; + } + } + + /// + /// Represents the container for one packte in the buffer. + /// + public struct JitterBufferPacket + { + /// + /// Data bytes contained in the packet + /// + public byte[] data; + + /// + /// Length of the packet in bytes + /// + public int len; + + /// + /// Timestamp for the packet + /// + public long timestamp; + + /// + /// Time covered by the packet (same units as timestamp) + /// + public long span; + + /// + /// RTP Sequence number if available (0 otherwise) + /// + public long sequence; + + /// + /// Put whatever data you like here (it's ignored by the jitter buffer) + /// + public long user_data; + } + + + /// + /// Timestamp of what we will *get* next + /// + long pointer_timestamp; + + /// + /// Useful for getting the next packet with the same timestamp (for fragmented media) + /// + long last_returned_timestamp; + + /// + /// Estimated time the next get() will be called + /// + long next_stop; + + /// + /// Amount of data we think is still buffered by the application (timestamp units) + /// + long buffered; + + /// + /// Packets stored in the buffer + /// + JitterBufferPacket[] packets = new JitterBufferPacket[MAX_BUFFER_SIZE]; + + /// + /// Packet arrival time (0 means it was late, even though it's a valid timestamp) + /// + long[] arrival = new long[MAX_BUFFER_SIZE]; + + /// + /// Callback for destroying a packet + /// + public Action DestroyBufferCallback; + + /// + /// Size of the steps when adjusting buffering (timestamp units) + /// + public int delay_step; + /// + /// Size of the packet loss concealment "units" + /// + int concealment_size; + /// + /// True if state was just reset + /// + bool reset_state; + /// + /// How many frames we want to keep in the buffer (lower bound) + /// + int buffer_margin; + /// + /// How late must a packet be for it not to be considered at all + /// + int late_cutoff; + + /// + /// An interpolation is requested by + /// + int interp_requested; + + /// + /// Whether to automatically adjust the delay at any time + /// + bool auto_adjust; + + + /// + /// Don't use those directly + /// + TimingBuffer[] _tb = new TimingBuffer[MAX_BUFFERS]; + /// + /// Storing arrival time of latest frames so we can compute some stats + /// + TimingBuffer[] timeBuffers = new TimingBuffer[MAX_BUFFERS]; + /// + /// Total window over which the late frames are counted + /// + public int window_size; + /// + /// Sub-window size for faster computation + /// + int subwindow_size; + /// + /// Absolute maximum amount of late packets tolerable (in percent) + /// + int max_late_rate; + /// + /// Latency equivalent of losing one percent of packets + /// + public int latency_tradeoff; + /// + /// Latency equivalent of losing one percent of packets (automatic default) + /// + public int auto_tradeoff; + + /// + /// Number of consecutive lost packets + /// + int lost_count; + + private void FreeBuffer(byte[] buffer) + { + } + + private byte[] AllocBuffer(long size) + { + return new byte[size]; + } + + /// + /// Initializes the jitterbuffer with a given . + /// + /// + public void Init(int step_size) + { + if (step_size <= 0) + throw new ArgumentOutOfRangeException("step_size"); + + int i; + int tmp; + for (i = 0; i < MAX_BUFFER_SIZE; i++) + packets[i].data = null; + + for (i = 0; i < MAX_BUFFERS; i++) + _tb[i] = new TimingBuffer(); + + delay_step = step_size; + concealment_size = step_size; + /*FIXME: Should this be 0 or 1?*/ + buffer_margin = 0; + late_cutoff = 50; + DestroyBufferCallback = null; + latency_tradeoff = 0; + auto_adjust = true; + tmp = 4; + SetMaxLateRate(tmp); + Reset(); + } + + void SetMaxLateRate(int maxLateRate) + { + max_late_rate = maxLateRate; + window_size = 100 * TOP_DELAY / max_late_rate; + subwindow_size = window_size / MAX_BUFFERS; + } + + void Reset() + { + int i; + for (i = 0; i < MAX_BUFFER_SIZE; i++) + { + if (packets[i].data != null) + { + if (DestroyBufferCallback != null) + DestroyBufferCallback(packets[i].data); + else + FreeBuffer(packets[i].data); + packets[i].data = null; + } + } + /* Timestamp is actually undefined at this point */ + pointer_timestamp = 0; + next_stop = 0; + reset_state = true; + lost_count = 0; + buffered = 0; + auto_tradeoff = 32000; + + for (i = 0; i < MAX_BUFFERS; i++) + { + _tb[i].Init(); + timeBuffers[i] = _tb[i]; + } + /*fprintf (stderr, "reset\n");*/ + } + + /// + /// Based on available data, this computes the optimal delay for the jitter buffer. + /// The optimised function is in timestamp units and is: + /// cost = delay + late_factor*[number of frames that would be late if we used that delay] + /// + /// + short ComputeOptDelay() + { + int i; + short opt = 0; + int best_cost = 0x7fffffff; + int late = 0; + int[] pos = new int[MAX_BUFFERS]; + int tot_count; + float late_factor; + bool penalty_taken = false; + int best = 0; + int worst = 0; + int deltaT; + TimingBuffer[] tb = _tb; + + /* Number of packet timings we have received (including those we didn't keep) */ + tot_count = 0; + for (i = 0; i < MAX_BUFFERS; i++) + tot_count += tb[i].curr_count; + if (tot_count == 0) + return 0; + + /* Compute cost for one lost packet */ + if (latency_tradeoff != 0) + late_factor = latency_tradeoff * 100.0f / tot_count; + else + late_factor = auto_tradeoff * window_size / tot_count; + + /*fprintf(stderr, "late_factor = %f\n", late_factor);*/ + for (i = 0; i < MAX_BUFFERS; i++) + pos[i] = 0; + + /* Pick the TOP_DELAY "latest" packets (doesn't need to actually be late + for the current settings) */ + for (i = 0; i < TOP_DELAY; i++) + { + int j; + int next = -1; + int latest = 32767; + /* Pick latest amoung all sub-windows */ + for (j = 0; j < MAX_BUFFERS; j++) + { + if (pos[j] < tb[j].filled && tb[j].timing[pos[j]] < latest) + { + next = j; + latest = tb[j].timing[pos[j]]; + } + } + if (next != -1) + { + int cost; + + if (i == 0) + worst = latest; + best = latest; + latest = RoundDown(latest, delay_step); + pos[next]++; + + /* Actual cost function that tells us how bad using this delay would be */ + cost = (int)(-latest + late_factor * late); + /*fprintf(stderr, "cost %d = %d + %f * %d\n", cost, -latest, late_factor, late);*/ + if (cost < best_cost) + { + best_cost = cost; + opt = (short)latest; + } + } + else + { + break; + } + + /* For the next timing we will consider, there will be one more late packet to count */ + late++; + /* Two-frame penalty if we're going to increase the amount of late frames (hysteresis) */ + if (latest >= 0 && !penalty_taken) + { + penalty_taken = true; + late += 4; + } + } + + deltaT = best - worst; + /* This is a default "automatic latency tradeoff" when none is provided */ + auto_tradeoff = 1 + deltaT / TOP_DELAY; + /*fprintf(stderr, "auto_tradeoff = %d (%d %d %d)\n", auto_tradeoff, best, worst, i);*/ + + /* FIXME: Compute a short-term estimate too and combine with the long-term one */ + + /* Prevents reducing the buffer size when we haven't really had much data */ + if (tot_count < TOP_DELAY && opt > 0) + return 0; + return opt; + } + + /// + /// Take the following timing into consideration for future calculations + /// + /// + void UpdateTimings(int timing) + { + if (timing < short.MinValue) + timing = short.MinValue; + if (timing > short.MaxValue) + timing = short.MaxValue; + short localTiming = (short)timing; + /* If the current sub-window is full, perform a rotation and discard oldest sub-widow */ + if (timeBuffers[0].curr_count >= subwindow_size) + { + int i; + /*fprintf(stderr, "Rotate buffer\n");*/ + TimingBuffer tmp = timeBuffers[MAX_BUFFERS - 1]; + for (i = MAX_BUFFERS - 1; i >= 1; i--) + timeBuffers[i] = timeBuffers[i - 1]; + timeBuffers[0] = tmp; + timeBuffers[0].Init(); + } + timeBuffers[0].Add(localTiming); + } + + /// + /// Put one packet into the jitter buffer + /// + /// + public void Put(JitterBufferPacket packet) + { + int i, j; + bool late; + /*fprintf (stderr, "put packet %d %d\n", timestamp, span);*/ + + // Cleanup buffer (remove old packets that weren't played) + if (!reset_state) + { + for (i = 0; i < MAX_BUFFER_SIZE; i++) + { + /* Make sure we don't discard a "just-late" packet in case we want to play it next (if we interpolate). */ + if (packets[i].data != null && (packets[i].timestamp + packets[i].span) <= pointer_timestamp) + { + /*fprintf (stderr, "cleaned (not played)\n");*/ + if (DestroyBufferCallback != null) + DestroyBufferCallback(packets[i].data); + else + FreeBuffer(packets[i].data); + packets[i].data = null; + } + } + } + + /*fprintf(stderr, "arrival: %d %d %d\n", packet.timestamp, next_stop, pointer_timestamp);*/ + /* Check if packet is late (could still be useful though) */ + if (!reset_state && packet.timestamp < next_stop) + { + UpdateTimings(((int)packet.timestamp) - ((int)next_stop) - buffer_margin); + late = true; + } + else + { + late = false; + } + + /* For some reason, the consumer has failed the last 20 fetches. Make sure this packet is + * used to resync. */ + if (lost_count > 20) + { + Reset(); + } + + /* Only insert the packet if it's not hopelessly late (i.e. totally useless) */ + if (reset_state || (packet.timestamp + packet.span + delay_step) >= pointer_timestamp) + { + + /*Find an empty slot in the buffer*/ + for (i = 0; i < MAX_BUFFER_SIZE; i++) + { + if (packets[i].data == null) + break; + } + + /*No place left in the buffer, need to make room for it by discarding the oldest packet */ + if (i == MAX_BUFFER_SIZE) + { + long earliest = packets[0].timestamp; + i = 0; + for (j = 1; j < MAX_BUFFER_SIZE; j++) + { + if (packets[i].data == null || packets[j].timestamp < earliest) + { + earliest = packets[j].timestamp; + i = j; + } + } + if (DestroyBufferCallback != null) + DestroyBufferCallback(packets[i].data); + else + FreeBuffer(packets[i].data); + packets[i].data = null; + /*fprintf (stderr, "Buffer is full, discarding earliest frame %d (currently at %d)\n", timestamp, pointer_timestamp);*/ + } + + /* Copy packet in buffer */ + if (DestroyBufferCallback != null) + { + packets[i].data = packet.data; + } + else + { + packets[i].data = AllocBuffer(packet.len); + for (j = 0; j < packet.len; j++) + packets[i].data[j] = packet.data[j]; + } + packets[i].timestamp = packet.timestamp; + packets[i].span = packet.span; + packets[i].len = packet.len; + packets[i].sequence = packet.sequence; + packets[i].user_data = packet.user_data; + if (reset_state || late) + arrival[i] = 0; + else + arrival[i] = next_stop; + } + } + + /// + /// Packet has been retrieved + /// + public const int JITTER_BUFFER_OK = 0; + + /// + /// Packet is lost or is late + /// + public const int JITTER_BUFFER_MISSING = 1; + + /// + /// A "fake" packet is meant to be inserted here to increase buffering + /// + public const int JITTER_BUFFER_INSERTION = 2; + + /// + /// There was an error in the jitter buffer + /// + public const int JITTER_BUFFER_INTERNAL_ERROR = -1; + + /// + /// Invalid argument + /// + public const int JITTER_BUFFER_BAD_ARGUMENT = -2; + + /// + /// Get one packet from the jitter buffer + /// + /// + /// + /// + /// + public int Get(ref JitterBufferPacket packet, int desired_span, out int start_offset) + { + if (desired_span <= 0) + throw new ArgumentOutOfRangeException("desired_span"); + + int i; + long j; + short opt; + + start_offset = 0; + + /* Syncing on the first call */ + if (reset_state) + { + bool found = false; + /* Find the oldest packet */ + long oldest = 0; + for (i = 0; i < MAX_BUFFER_SIZE; i++) + { + if (packets[i].data != null && (!found || packets[i].timestamp < oldest)) + { + oldest = packets[i].timestamp; + found = true; + } + } + if (found) + { + reset_state = false; + pointer_timestamp = oldest; + next_stop = oldest; + } + else + { + packet.timestamp = 0; + packet.span = interp_requested; + return JITTER_BUFFER_MISSING; + } + } + + last_returned_timestamp = pointer_timestamp; + + if (interp_requested != 0) + { + packet.timestamp = pointer_timestamp; + packet.span = interp_requested; + + /* Increment the pointer because it got decremented in the delay update */ + pointer_timestamp += interp_requested; + packet.len = 0; + /*fprintf (stderr, "Deferred interpolate\n");*/ + + interp_requested = 0; + + buffered = packet.span - desired_span; + + return JITTER_BUFFER_INSERTION; + } + + /* Searching for the packet that fits best */ + + /* Search the buffer for a packet with the right timestamp and spanning the whole current chunk */ + for (i = 0; i < MAX_BUFFER_SIZE; i++) + { + if (packets[i].data != null && packets[i].timestamp == pointer_timestamp && (packets[i].timestamp + packets[i].span) >= (pointer_timestamp + desired_span)) + break; + } + + /* If no match, try for an "older" packet that still spans (fully) the current chunk */ + if (i == MAX_BUFFER_SIZE) + { + for (i = 0; i < MAX_BUFFER_SIZE; i++) + { + if (packets[i].data != null && packets[i].timestamp <= pointer_timestamp && (packets[i].timestamp + packets[i].span) >= (pointer_timestamp + desired_span)) + break; + } + } + + /* If still no match, try for an "older" packet that spans part of the current chunk */ + if (i == MAX_BUFFER_SIZE) + { + for (i = 0; i < MAX_BUFFER_SIZE; i++) + { + if (packets[i].data != null && packets[i].timestamp <= pointer_timestamp && (packets[i].timestamp + packets[i].span) > pointer_timestamp) + break; + } + } + + /* If still no match, try for earliest packet possible */ + if (i == MAX_BUFFER_SIZE) + { + bool found = false; + long best_time = 0; + long best_span = 0; + int besti = 0; + for (i = 0; i < MAX_BUFFER_SIZE; i++) + { + /* check if packet starts within current chunk */ + if (packets[i].data != null && packets[i].timestamp < (pointer_timestamp + desired_span) && (packets[i].timestamp >= pointer_timestamp)) + { + if (!found || packets[i].timestamp < best_time || (packets[i].timestamp == best_time && packets[i].span > best_span)) + { + best_time = packets[i].timestamp; + best_span = packets[i].span; + besti = i; + found = true; + } + } + } + if (found) + { + i = besti; + /*fprintf (stderr, "incomplete: %d %d %d %d\n", packets[i].timestamp, pointer_timestamp, chunk_size, packets[i].span);*/ + } + } + + /* If we find something */ + if (i != MAX_BUFFER_SIZE) + { + int offset; + + /* We (obviously) haven't lost this packet */ + lost_count = 0; + + /* In this case, 0 isn't as a valid timestamp */ + if (arrival[i] != 0) + { + UpdateTimings(((int)packets[i].timestamp) - ((int)arrival[i]) - buffer_margin); + } + + + /* Copy packet */ + if (DestroyBufferCallback != null) + { + packet.data = packets[i].data; + packet.len = packets[i].len; + } + else + { + if (packets[i].len > packet.len) + { + Debug.WriteLine("JitterBuffer.Get(): packet too large to fit. Size is", packets[i].len); + } + else + { + packet.len = packets[i].len; + } + for (j = 0; j < packet.len; j++) + packet.data[j] = packets[i].data[j]; + /* Remove packet */ + FreeBuffer(packets[i].data); + } + packets[i].data = null; + /* Set timestamp and span (if requested) */ + offset = (int)packets[i].timestamp - (int)pointer_timestamp; + if (start_offset != 0) + start_offset = offset; + else if (offset != 0) + Debug.WriteLine("JitterBuffer.Get(): discarding non-zero start_offset", offset); + + packet.timestamp = packets[i].timestamp; + last_returned_timestamp = packet.timestamp; + + packet.span = packets[i].span; + packet.sequence = packets[i].sequence; + packet.user_data = packets[i].user_data; + packet.len = packets[i].len; + /* Point to the end of the current packet */ + pointer_timestamp = packets[i].timestamp + packets[i].span; + + buffered = packet.span - desired_span; + + if (start_offset != 0) + buffered += start_offset; + + return JITTER_BUFFER_OK; + } + + + /* If we haven't found anything worth returning */ + + /*fprintf (stderr, "not found\n");*/ + lost_count++; + /*fprintf (stderr, "m");*/ + /*fprintf (stderr, "lost_count = %d\n", lost_count);*/ + + opt = ComputeOptDelay(); + + /* Should we force an increase in the buffer or just do normal interpolation? */ + if (opt < 0) + { + /* Need to increase buffering */ + + /* Shift histogram to compensate */ + ShiftTimings((short)-opt); + + packet.timestamp = pointer_timestamp; + packet.span = -opt; + /* Don't move the pointer_timestamp forward */ + packet.len = 0; + + buffered = packet.span - desired_span; + return JITTER_BUFFER_INSERTION; + /*pointer_timestamp -= delay_step;*/ + /*fprintf (stderr, "Forced to interpolate\n");*/ + } + else + { + /* Normal packet loss */ + packet.timestamp = pointer_timestamp; + + desired_span = RoundDown(desired_span, concealment_size); + packet.span = desired_span; + pointer_timestamp += desired_span; + packet.len = 0; + + buffered = packet.span - desired_span; + return JITTER_BUFFER_MISSING; + /*fprintf (stderr, "Normal loss\n");*/ + } + } + + /** Compensate all timings when we do an adjustment of the buffering */ + void ShiftTimings(short amount) + { + int i, j; + for (i = 0; i < MAX_BUFFERS; i++) + { + for (j = 0; j < timeBuffers[i].filled; j++) + timeBuffers[i].timing[j] += amount; + } + } + + /// + /// Let the jitter buffer know it's the right time to adjust the buffering delay to the network conditions + /// + /// + int UpdateDelay() + { + short opt = ComputeOptDelay(); + /*fprintf(stderr, "opt adjustment is %d ", opt);*/ + + if (opt < 0) + { + ShiftTimings((short)-opt); + + pointer_timestamp += opt; + interp_requested = -opt; + /*fprintf (stderr, "Decision to interpolate %d samples\n", -opt);*/ + } + else if (opt > 0) + { + ShiftTimings((short)-opt); + pointer_timestamp += opt; + /*fprintf (stderr, "Decision to drop %d samples\n", opt);*/ + } + + return opt; + } + + /// + /// Call this method to indicate one step in time (one tick). + /// + public void Tick() + { + /* Automatically-adjust the buffering delay if requested */ + if (auto_adjust) + UpdateDelay(); + + if (buffered >= 0) + { + next_stop = pointer_timestamp - buffered; + } + else + { + next_stop = pointer_timestamp; + Debug.WriteLine("jitter buffer sees negative buffering, your code might be broken. Value is ", buffered); + } + buffered = 0; + } + } + + /// + /// Jitter buffer designed for a speex decoder. + /// + public class SpeexJitterBuffer + { + private readonly SpeexDecoder decoder; + private readonly JitterBuffer buffer = new JitterBuffer(); + private JitterBuffer.JitterBufferPacket outPacket; + private JitterBuffer.JitterBufferPacket inPacket; + + /// + /// Creates a new instance using the given + /// + /// + public SpeexJitterBuffer(SpeexDecoder decoder) + { + if (decoder == null) + throw new ArgumentNullException("decoder"); + + this.decoder = decoder; + + inPacket.sequence = 0; + inPacket.span = 1; + inPacket.timestamp = 1; + + buffer.DestroyBufferCallback = (x) => + { + // GC handles that + }; + buffer.Init(1); + } + + /// + /// Returns the next decoded frame from the buffer. + /// + /// + public void Get(short[] decodedFrame) + { + if (decodedFrame == null) + throw new ArgumentNullException("decodedFrame"); + + if (outPacket.data == null) + { + outPacket.data = new byte[decodedFrame.Length * 2]; + } + else + Array.Clear(outPacket.data, 0, outPacket.data.Length); + + outPacket.len = outPacket.data.Length; + + int temp; + if (buffer.Get(ref outPacket, 1, out temp) != JitterBuffer.JITTER_BUFFER_OK) + { + // no packet found + decoder.Decode(null, 0, 0, decodedFrame, 0, true); + } + else + { + decoder.Decode(outPacket.data, 0, outPacket.len, decodedFrame, 0, false); + } + + buffer.Tick(); + } + + /// + /// Puts the into the buffer. Note that the given byte array + /// is not copied so you transfer ownership to the buffer. + /// + /// + public void Put(byte[] frameData) + { + if (frameData == null) + throw new ArgumentNullException("frameData"); + + inPacket.data = frameData; + inPacket.len = frameData.Length; + inPacket.timestamp++; + + buffer.Put(inPacket); + } + } +} diff --git a/Assets/Scripts/OpenTS2/NSpeex/JitterBuffer.cs.meta b/Assets/Scripts/OpenTS2/NSpeex/JitterBuffer.cs.meta new file mode 100644 index 00000000..1ff46ed6 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/JitterBuffer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8b133bc5bffb4f447ad24e7f14cc430b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/NSpeex/LbrLspQuant.cs b/Assets/Scripts/OpenTS2/NSpeex/LbrLspQuant.cs new file mode 100644 index 00000000..8e43ea63 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/LbrLspQuant.cs @@ -0,0 +1,109 @@ +// +// Copyright (C) 2003 Jean-Marc Valin +// Copyright (C) 1999-2003 Wimba S.A., All Rights Reserved. +// Copyright (C) 2008 Filip Navara +// Copyright (C) 2009-2010 Christoph Frschl +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// - Neither the name of the Xiph.org Foundation nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +using System; + +namespace NSpeex +{ + /// + /// LSP Quantisation and Unquantisation (Lbr) + /// + internal class LbrLspQuant : LspQuant + { + /// + /// Line Spectral Pair Quantification (Lbr). + /// + public sealed override void Quant(float[] lsp, float[] qlsp, int order, Bits bits) + { + int i; + float tmp1, tmp2; + int id; + float[] quant_weight = new float[NSpeex.LspQuant.MAX_LSP_SIZE]; + + for (i = 0; i < order; i++) + qlsp[i] = lsp[i]; + quant_weight[0] = 1 / (qlsp[1] - qlsp[0]); + quant_weight[order - 1] = 1 / (qlsp[order - 1] - qlsp[order - 2]); + for (i = 1; i < order - 1; i++) + { + tmp1 = 1 / ((.15f + qlsp[i] - qlsp[i - 1]) * (.15f + qlsp[i] - qlsp[i - 1])); + tmp2 = 1 / ((.15f + qlsp[i + 1] - qlsp[i]) * (.15f + qlsp[i + 1] - qlsp[i])); + quant_weight[i] = (tmp1 > tmp2) ? tmp1 : tmp2; + } + + for (i = 0; i < order; i++) + qlsp[i] -= ((Single?)(.25d * i + .25d)).Value; + for (i = 0; i < order; i++) + qlsp[i] *= 256; + + id = NSpeex.LspQuant.Lsp_quant(qlsp, 0, + NSpeex.Codebook_Constants.cdbk_nb, + NSpeex.Codebook_Constants.NB_CDBK_SIZE, order); + bits.Pack(id, 6); + + for (i = 0; i < order; i++) + qlsp[i] *= 2; + id = NSpeex.LspQuant.Lsp_weight_quant(qlsp, 0, quant_weight, 0, + NSpeex.Codebook_Constants.cdbk_nb_low1, + NSpeex.Codebook_Constants.NB_CDBK_SIZE_LOW1, 5); + bits.Pack(id, 6); + id = NSpeex.LspQuant.Lsp_weight_quant(qlsp, 5, quant_weight, 5, + NSpeex.Codebook_Constants.cdbk_nb_high1, + NSpeex.Codebook_Constants.NB_CDBK_SIZE_HIGH1, 5); + bits.Pack(id, 6); + + for (i = 0; i < order; i++) + qlsp[i] *= ((Single?)0.0019531d).Value; + for (i = 0; i < order; i++) + qlsp[i] = lsp[i] - qlsp[i]; + } + + /// + /// Line Spectral Pair Unquantification (Lbr). + /// + /// + /// - + /// + /// - + public sealed override void Unquant(float[] lsp, int order, + Bits bits) + { + for (int i = 0; i < order; i++) + lsp[i] = .25f * i + .25f; + UnpackPlus(lsp, NSpeex.Codebook_Constants.cdbk_nb, bits, 0.0039062f, 10, 0); + UnpackPlus(lsp, NSpeex.Codebook_Constants.cdbk_nb_low1, bits, 0.0019531f, 5, 0); + UnpackPlus(lsp, NSpeex.Codebook_Constants.cdbk_nb_high1, bits, 0.0019531f, 5, 5); + } + } +} diff --git a/Assets/Scripts/OpenTS2/NSpeex/LbrLspQuant.cs.meta b/Assets/Scripts/OpenTS2/NSpeex/LbrLspQuant.cs.meta new file mode 100644 index 00000000..ce0cacd7 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/LbrLspQuant.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 700413da81d182247b6338c0f5f973d1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/NSpeex/LittleEndian.cs b/Assets/Scripts/OpenTS2/NSpeex/LittleEndian.cs new file mode 100644 index 00000000..1a93b159 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/LittleEndian.cs @@ -0,0 +1,169 @@ +using System; +using System.IO; +using System.Text; +namespace NSpeex +{ + public class LittleEndian + { + + private static byte[] Convert(byte[] data) + { + if (!BitConverter.IsLittleEndian) + { + // revert order + int size = data.Length; + byte[] result = new byte[size]; + for (int i = 0; i < data.Length; i++) + { + result[i] = data[size - 1 - i]; + } + return result; + + } + else + { + return data; + } + } + + public static void WriteShort(byte[] buf, int offset, short value) + { + // a short has 2 bytes + byte[] data = BitConverter.GetBytes(value); + byte[] data2 = Convert(data); + Array.Copy(data2, 0, buf, offset, 2); + } + + public static void WriteShort(Stream stream, short value) + { + // a short has 2 bytes + byte[] data = BitConverter.GetBytes(value); + byte[] data2 = Convert(data); + stream.Write(data2, 0, data2.Length); + } + + + /// + /// write a int value to buf where index is offset, + /// that means from buf[offset] to buf[offset + 3] is value data + /// + public static void WriteInt(byte[] buf, int offset, int value) + { + byte[] data = BitConverter.GetBytes(value); + byte[] data2 = Convert(data); + Array.Copy(data2, 0, buf, offset, 4); + } + + public static void WriteInt(Stream stream, int value) + { + byte[] data = BitConverter.GetBytes(value); + byte[] data2 = Convert(data); + stream.Write(data2, 0, data2.Length); + } + + + /// + /// write a long value to buf where index is offset, + /// that means from buf[offset] to buf[offset + 7] is value data + /// + public static void WriteLong(byte[] buf, int offset, long value) + { + byte[] data = BitConverter.GetBytes(value); + byte[] data2 = Convert(data); + Array.Copy(data2, 0, buf, offset, 8); + } + + public static void WriteLong(Stream stream, long value) + { + byte[] data = BitConverter.GetBytes(value); + byte[] data2 = Convert(data); + stream.Write(data2, 0, data2.Length); + } + + /// + /// write a string value to buf where index is offset, + /// that means from buf[offset] to buf[offset + value.Length] is value data + /// + public static void WriteString(byte[] buf, int offset, string value) + { + byte[] data = UTF8Encoding.UTF8.GetBytes(value); + Array.Copy(data, 0, buf, offset, data.Length); + } + + public static void WriteString(Stream stram, string value) + { + byte[] data = UTF8Encoding.UTF8.GetBytes(value); + stram.Write(data, 0, data.Length); + } + + public static short ReadShort(byte[] buf, int offset) + { + byte[] data = new byte[2] { 0, 0 }; + Array.Copy(buf, offset, data, 0, 2); + byte[] data2 = Convert(data); + return BitConverter.ToInt16(data2, 0); + } + public static short ReadShort(Stream stream) + { + byte[] data = new byte[2] { 0, 0 }; + stream.Read(data, 0, 2); + byte[] data2 = Convert(data); + return BitConverter.ToInt16(data2, 0); + } + + + /// + /// read value from buf where index is offset + /// + public static int ReadInt(byte[] buf, int offset) + { + byte[] data = new byte[4] { 0, 0, 0, 0 }; + Array.Copy(buf, offset, data, 0, 4); + byte[] data2 = Convert(data); + return BitConverter.ToInt32(data2, 0); + } + public static int ReadInt(Stream stream) + { + byte[] data = new byte[4] { 0, 0, 0, 0 }; + stream.Read(data, 0, 4); + byte[] data2 = Convert(data); + return BitConverter.ToInt32(data2, 0); + } + + + /// + /// read value from buf where index is offset + /// + public static long ReadLong(byte[] buf, int offset) + { + byte[] data = new byte[8] { 0, 0, 0, 0, 0, 0, 0, 0 }; + Array.Copy(buf, offset, data, 0, 8); + byte[] data2 = Convert(data); + return BitConverter.ToInt64(data2, 0); + } + + public static long ReadLong(Stream stream) + { + byte[] data = new byte[8] { 0, 0, 0, 0, 0, 0, 0, 0 }; + stream.Read(data, 0, 8); + byte[] data2 = Convert(data); + return BitConverter.ToInt64(data2, 0); + } + + /// + /// read value from buf where index is offset and length is size + /// + public static string ReadString(byte[] buf, int offset, int size) + { + return UTF8Encoding.UTF8.GetString(buf, offset, size); + } + + public static string ReadString(Stream stream, int size) + { + byte[] data = new byte[size]; + stream.Read(data, 0, size); + return UTF8Encoding.UTF8.GetString(data, 0, size); + } + + } +} diff --git a/Assets/Scripts/OpenTS2/NSpeex/LittleEndian.cs.meta b/Assets/Scripts/OpenTS2/NSpeex/LittleEndian.cs.meta new file mode 100644 index 00000000..2fe28513 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/LittleEndian.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1ee1274dd1d885a4dba4b631123d8d7b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/NSpeex/Lpc.cs b/Assets/Scripts/OpenTS2/NSpeex/Lpc.cs new file mode 100644 index 00000000..3cc5f936 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/Lpc.cs @@ -0,0 +1,102 @@ +// +// Copyright (C) 2003 Jean-Marc Valin +// Copyright (C) 1999-2003 Wimba S.A., All Rights Reserved. +// Copyright (C) 2008 Filip Navara +// Copyright (C) 2009-2010 Christoph Frschl +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// - Neither the name of the Xiph.org Foundation nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +using System; + +namespace NSpeex +{ + /// + /// LPC - and Reflection Coefficients. + /// + /// The next two functions calculate linear prediction coefficients and/or the + /// related reflection coefficients from the first P_MAX+1 values of the + /// autocorrelation function. + /// + /// Invented by N. Levinson in 1947, modified by J. Durbin in 1959. + /// + internal class Lpc + { + /// + /// Returns minimum mean square error. + /// + /// minimum mean square error. + public static float Wld(float[] lpc, float[] ac, float[] xref, int p) + { + int i, j; + float r, error = ac[0]; + if (ac[0] == 0) + { + for (i = 0; i < p; i++) + xref[i] = 0; + return 0; + } + for (i = 0; i < p; i++) + { + // Sum up this iteration's reflection coefficient. + r = -ac[i + 1]; + for (j = 0; j < i; j++) + r -= lpc[j] * ac[i - j]; + xref[i] = r /= error; + // Update LPC coefficients and total error. + lpc[i] = r; + for (j = 0; j < i / 2; j++) + { + float tmp = lpc[j]; + lpc[j] += r * lpc[i - 1 - j]; + lpc[i - 1 - j] += r * tmp; + } + if ((i % 2) != 0) + lpc[j] += lpc[j] * r; + error *= ((Single?)1.0d).Value - r * r; + } + return error; + } + + /// + /// Compute the autocorrelation ,--, ac(i) = > x(n)/// x(n-i) for all n `--' + /// for lags between 0 and lag-1, and x == 0 outside 0...n-1 + /// + public static void Autocorr(float[] x, float[] ac, int lag, int n) + { + float d; + int i; + while (lag-- > 0) + { + for (i = lag, d = 0; i < n; i++) + d += x[i] * x[i - lag]; + ac[lag] = d; + } + } + } +} diff --git a/Assets/Scripts/OpenTS2/NSpeex/Lpc.cs.meta b/Assets/Scripts/OpenTS2/NSpeex/Lpc.cs.meta new file mode 100644 index 00000000..68bdb5d4 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/Lpc.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8a50470d872065448b2a0f3ad9580249 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/NSpeex/Lsp.cs b/Assets/Scripts/OpenTS2/NSpeex/Lsp.cs new file mode 100644 index 00000000..30ec5594 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/Lsp.cs @@ -0,0 +1,286 @@ +// +// Copyright (C) 2003 Jean-Marc Valin +// Copyright (C) 1999-2003 Wimba S.A., All Rights Reserved. +// Copyright (C) 2008 Filip Navara +// Copyright (C) 2009-2010 Christoph Frschl +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// - Neither the name of the Xiph.org Foundation nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +using System; + +namespace NSpeex +{ + /// + /// Line Spectral Pair + /// + internal class Lsp + { + private float[] pw; + + /// + /// Constructor + /// + /// + public Lsp() + { + pw = new float[42]; + } + + /// + /// This function evaluates a series of Chebyshev polynomials. + /// + /// the value of the polynomial at point x. + public static float Cheb_poly_eva(float[] coef, float x, int m) + { + int i; + float sum; + float[] T; + int m2 = m >> 1; + /* Allocate memory for Chebyshev series formulation */ + T = new float[m2 + 1]; + /* Initialise values */ + T[0] = 1; + T[1] = x; + /* Evaluate Chebyshev series formulation using iterative approach */ + /* Evaluate polynomial and return value also free memory space */ + sum = coef[m2] + coef[m2 - 1] * x; + x *= 2; + for (i = 2; i <= m2; i++) + { + T[i] = x * T[i - 1] - T[i - 2]; + sum += coef[m2 - i] * T[i]; + } + return sum; + } + + /// + /// This function converts LPC coefficients to LSP coefficients. + /// + /// the number of roots (the LSP coefs are returned in the array). + public static int Lpc2lsp(float[] a, int lpcrdr, float[] freq, int nb, float delta) + { + float psuml, psumr, psumm, temp_xr, xl, xr, xm = 0; + float temp_psumr; + int i, j, m, flag, k; + float[] Q; // ptrs for memory allocation + float[] P; + int px; // ptrs of respective P'(z) & Q'(z) + int qx; + int p; + int q; + float[] pt; // ptr used for cheb_poly_eval() whether P' or Q' + int roots = 0; // DR 8/2/94: number of roots found + flag = 1; // program is searching for a root when, 1 else has found + // one + m = lpcrdr / 2; // order of P'(z) & Q'(z) polynomials + + /* Allocate memory space for polynomials */ + Q = new float[m + 1]; + P = new float[m + 1]; + + /* + * determine P'(z)'s and Q'(z)'s coefficients where P'(z) = P(z)/(1 + + * z^(-1)) and Q'(z) = Q(z)/(1-z^(-1)) + */ + + px = 0; /* initialise ptrs */ + qx = 0; + p = px; + q = qx; + P[px++] = 1.0f; + Q[qx++] = 1.0f; + for (i = 1; i <= m; i++) + { + P[px++] = a[i] + a[lpcrdr + 1 - i] - P[p++]; + Q[qx++] = a[i] - a[lpcrdr + 1 - i] + Q[q++]; + } + px = 0; + qx = 0; + for (i = 0; i < m; i++) + { + P[px] = 2 * P[px]; + Q[qx] = 2 * Q[qx]; + px++; + qx++; + } + px = 0; /* re-initialise ptrs */ + qx = 0; + + /* + * Search for a zero in P'(z) polynomial first and then alternate to + * Q'(z). Keep alternating between the two polynomials as each zero is + * found + */ + + xr = 0; /* initialise xr to zero */ + xl = 1.0f; /* start at point xl = 1 */ + + for (j = 0; j < lpcrdr; j++) + { + if (j % 2 != 0) /* determines whether P' or Q' is eval. */ + pt = Q; + else + pt = P; + + psuml = Cheb_poly_eva(pt, xl, lpcrdr); /* evals poly. at xl */ + flag = 1; + while ((flag == 1) && (xr >= -1.0d)) + { + float dd; + /* Modified by JMV to provide smaller steps around x=+-1 */ + dd = (float)(delta * (1 - .9d * xl * xl)); + if (Math.Abs(psuml) < .2d) + dd *= ((Single?).5d).Value; + + xr = xl - dd; /* interval spacing */ + psumr = Cheb_poly_eva(pt, xr, lpcrdr); /* poly(xl-delta_x) */ + temp_psumr = psumr; + temp_xr = xr; + + /* + * if no sign change increment xr and re-evaluate poly(xr). + * Repeat til sign change. if a sign change has occurred the + * interval is bisected and then checked again for a sign change + * which determines in which interval the zero lies in. If there + * is no sign change between poly(xm) and poly(xl) set interval + * between xm and xr else set interval between xl and xr and + * repeat till root is located within the specified limits + */ + + if ((psumr * psuml) < 0.0d) + { + roots++; + + psumm = psuml; + for (k = 0; k <= nb; k++) + { + xm = (xl + xr) / 2; /* bisect the interval */ + psumm = Cheb_poly_eva(pt, xm, lpcrdr); + if (psumm * psuml > 0.0) + { + psuml = psumm; + xl = xm; + } + else + { + psumr = psumm; + xr = xm; + } + } + + /* once zero is found, reset initial interval to xr */ + freq[j] = xm; + xl = xm; + flag = 0; /* reset flag for next search */ + } + else + { + psuml = temp_psumr; + xl = temp_xr; + } + } + } + return roots; + } + + /// + /// Line Spectral Pair to Linear Prediction Coefficients + /// + public void Lsp2lpc(float[] freq, float[] ak, int lpcrdr) + { + int i, j; + float xout1, xout2, xin1, xin2; + int n1, n2, n3, n4 = 0; + int m = lpcrdr / 2; + + for (i = 0; i < 4 * m + 2; i++) + { + pw[i] = 0.0f; + } + + xin1 = 1.0f; + xin2 = 1.0f; + + /* + * reconstruct P(z) and Q(z) by cascading second order polynomials in + * form 1 - 2xz(-1) +z(-2), where x is the LSP coefficient + */ + for (j = 0; j <= lpcrdr; j++) + { + int i2 = 0; + + for (i = 0; i < m; i++, i2 += 2) + { + n1 = i * 4; + n2 = n1 + 1; + n3 = n2 + 1; + n4 = n3 + 1; + xout1 = xin1 - 2 * (freq[i2]) * pw[n1] + pw[n2]; + xout2 = xin2 - 2 * (freq[i2 + 1]) * pw[n3] + pw[n4]; + pw[n2] = pw[n1]; + pw[n4] = pw[n3]; + pw[n1] = xin1; + pw[n3] = xin2; + xin1 = xout1; + xin2 = xout2; + } + xout1 = xin1 + pw[n4 + 1]; + xout2 = xin2 - pw[n4 + 2]; + ak[j] = (xout1 + xout2) * 0.5f; + pw[n4 + 1] = xin1; + pw[n4 + 2] = xin2; + xin1 = 0.0f; + xin2 = 0.0f; + } + } + + /// + /// Makes sure the LSPs are stable. + /// + public static void Enforce_margin(float[] lsp, int len, float margin) + { + int i; + + if (lsp[0] < margin) + lsp[0] = margin; + + if (lsp[len - 1] > (float)System.Math.PI - margin) + lsp[len - 1] = (float)System.Math.PI - margin; + + for (i = 1; i < len - 1; i++) + { + if (lsp[i] < lsp[i - 1] + margin) + lsp[i] = lsp[i - 1] + margin; + + if (lsp[i] > lsp[i + 1] - margin) + lsp[i] = .5f * (lsp[i] + lsp[i + 1] - margin); + } + } + } +} diff --git a/Assets/Scripts/OpenTS2/NSpeex/Lsp.cs.meta b/Assets/Scripts/OpenTS2/NSpeex/Lsp.cs.meta new file mode 100644 index 00000000..d404b644 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/Lsp.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 95febb0fb22268542b8c83a77d371959 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/NSpeex/LspQuant.cs b/Assets/Scripts/OpenTS2/NSpeex/LspQuant.cs new file mode 100644 index 00000000..85fb3939 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/LspQuant.cs @@ -0,0 +1,135 @@ +// +// Copyright (C) 2003 Jean-Marc Valin +// Copyright (C) 1999-2003 Wimba S.A., All Rights Reserved. +// Copyright (C) 2008 Filip Navara +// Copyright (C) 2009-2010 Christoph Frschl +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// - Neither the name of the Xiph.org Foundation nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +namespace NSpeex +{ + /// + /// Abstract class that is the base for the various LSP Quantisation and + /// Unquantisation methods. + /// + internal abstract class LspQuant + { + protected const int MAX_LSP_SIZE = 20; + + protected internal LspQuant() + { + } + + /// + /// Line Spectral Pair Quantification. + /// + public abstract void Quant(float[] lsp, float[] qlsp, int order, Bits bits); + + /// + /// Line Spectral Pair Unquantification. + /// + public abstract void Unquant(float[] lsp, int order, Bits bits); + + /// + /// Read the next 6 bits from the buffer, and using the value read and the + /// given codebook, rebuild LSP table. + /// + protected internal void UnpackPlus(float[] lsp, int[] tab, Bits bits, float k, int ti, int li) + { + int id = bits.Unpack(6); + for (int i = 0; i < ti; i++) + lsp[i + li] += k * (float)tab[id * ti + i]; + } + + /// + /// LSP quantification Note: x is modified + /// + /// the index of the best match in the codebook (NB x is also + protected static internal int Lsp_quant(float[] x, int xs, int[] cdbk, int nbVec, int nbDim) + { + int i, j; + float dist, tmp; + float best_dist = 0; + int best_id = 0; + int ptr = 0; + for (i = 0; i < nbVec; i++) + { + dist = 0; + for (j = 0; j < nbDim; j++) + { + tmp = (x[xs + j] - cdbk[ptr++]); + dist += tmp * tmp; + } + if (dist < best_dist || i == 0) + { + best_dist = dist; + best_id = i; + } + } + + for (j = 0; j < nbDim; j++) + x[xs + j] -= cdbk[best_id * nbDim + j]; + + return best_id; + } + + /// + /// LSP weighted quantification Note: x is modified + /// + /// the index of the best match in the codebook (NB x is also + protected static internal int Lsp_weight_quant( + float[] x, int xs, + float[] weight, int ws, int[] cdbk, + int nbVec, int nbDim) + { + int i, j; + float dist, tmp; + float best_dist = 0; + int best_id = 0; + int ptr = 0; + for (i = 0; i < nbVec; i++) + { + dist = 0; + for (j = 0; j < nbDim; j++) + { + tmp = (x[xs + j] - cdbk[ptr++]); + dist += weight[ws + j] * tmp * tmp; + } + if (dist < best_dist || i == 0) + { + best_dist = dist; + best_id = i; + } + } + for (j = 0; j < nbDim; j++) + x[xs + j] -= cdbk[best_id * nbDim + j]; + return best_id; + } + } +} diff --git a/Assets/Scripts/OpenTS2/NSpeex/LspQuant.cs.meta b/Assets/Scripts/OpenTS2/NSpeex/LspQuant.cs.meta new file mode 100644 index 00000000..198140eb --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/LspQuant.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5145e11c021cb4e4b93f1aa712e3e710 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/NSpeex/Ltp.cs b/Assets/Scripts/OpenTS2/NSpeex/Ltp.cs new file mode 100644 index 00000000..886eff39 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/Ltp.cs @@ -0,0 +1,164 @@ +// +// Copyright (C) 2003 Jean-Marc Valin +// Copyright (C) 1999-2003 Wimba S.A., All Rights Reserved. +// Copyright (C) 2008 Filip Navara +// Copyright (C) 2009-2010 Christoph Frschl +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// - Neither the name of the Xiph.org Foundation nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +using System; + +namespace NSpeex +{ + /// + /// Abstract class that is the base for the various LTP (Long Term Prediction) + /// Quantisation and Unquantisation methods. + /// + internal abstract class Ltp + { + /// + /// Long Term Prediction Quantification. + /// + /// pitch + public abstract int Quant( + float[] target, float[] sw, int sws, float[] ak, + float[] awk1, float[] awk2, float[] exc, int es, int start, + int end, float pitch_coef, int p, int nsf, Bits bits, float[] exc2, + int e2s, float[] r, int complexity); + + /// + /// Long Term Prediction Unquantification. + /// + /// pitch + public abstract int Unquant( + float[] exc, int es, int start, + float pitch_coef, int nsf, float[] gain_val, Bits bits, + int count_lost, int subframe_offset, float last_pitch_gain); + + /// + /// Calculates the inner product of the given vectors. + /// > + /// the inner product of the given vectors. + protected static internal float Inner_prod( + float[] x, int xs, float[] y, int ys, int len) + { + int i; + float sum1 = 0, sum2 = 0, sum3 = 0, sum4 = 0; + for (i = 0; i < len; ) + { + sum1 += x[xs + i] * y[ys + i]; + sum2 += x[xs + i + 1] * y[ys + i + 1]; + sum3 += x[xs + i + 2] * y[ys + i + 2]; + sum4 += x[xs + i + 3] * y[ys + i + 3]; + i += 4; + } + return sum1 + sum2 + sum3 + sum4; + } + + /// + /// Find the n-best pitch in Open Loop. + /// + protected static internal void Open_loop_nbest_pitch( + float[] sw, int swIdx, int start, int end, int len, + int[] pitch, float[] gain, int N) + { + int i, j, k; + /* float corr=0; */ + /* float energy; */ + float[] best_score; + float e0; + float[] corr, energy, score; + + best_score = new float[N]; + corr = new float[end - start + 1]; + energy = new float[end - start + 2]; + score = new float[end - start + 1]; + for (i = 0; i < N; i++) + { + best_score[i] = -1; + gain[i] = 0; + pitch[i] = start; + } + energy[0] = Inner_prod(sw, swIdx - start, sw, swIdx - start, len); + e0 = Inner_prod(sw, swIdx, sw, swIdx, len); + for (i = start; i <= end; i++) + { + /* Update energy for next pitch */ + energy[i - start + 1] = energy[i - start] + sw[swIdx - i - 1] + * sw[swIdx - i - 1] - sw[swIdx - i + len - 1] + * sw[swIdx - i + len - 1]; + if (energy[i - start + 1] < 1) + energy[i - start + 1] = 1; + } + for (i = start; i <= end; i++) + { + corr[i - start] = 0; + score[i - start] = 0; + } + + for (i = start; i <= end; i++) + { + // Compute correlation + corr[i - start] = Inner_prod(sw, swIdx, sw, swIdx - i, len); + score[i - start] = corr[i - start] * corr[i - start] + / (energy[i - start] + 1); + } + for (i = start; i <= end; i++) + { + if (score[i - start] > best_score[N - 1]) + { + float g1, g; + g1 = corr[i - start] / (energy[i - start] + 10); + g = (float)Math.Sqrt(g1 * corr[i - start] + / (e0 + 10)); + if (g > g1) + g = g1; + if (g < 0) + g = 0; + for (j = 0; j < N; j++) + { + if (score[i - start] > best_score[j]) + { + for (k = N - 1; k > j; k--) + { + best_score[k] = best_score[k - 1]; + pitch[k] = pitch[k - 1]; + gain[k] = gain[k - 1]; + } + best_score[j] = score[i - start]; + pitch[j] = i; + gain[j] = g; + break; + } + } + } + } + } + } +} diff --git a/Assets/Scripts/OpenTS2/NSpeex/Ltp.cs.meta b/Assets/Scripts/OpenTS2/NSpeex/Ltp.cs.meta new file mode 100644 index 00000000..4622a11c --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/Ltp.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: adb5ae7eaead8a9479e910d5c4bc7ce3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/NSpeex/Ltp3Tap.cs b/Assets/Scripts/OpenTS2/NSpeex/Ltp3Tap.cs new file mode 100644 index 00000000..5ed72a63 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/Ltp3Tap.cs @@ -0,0 +1,360 @@ +// +// Copyright (C) 2003 Jean-Marc Valin +// Copyright (C) 1999-2003 Wimba S.A., All Rights Reserved. +// Copyright (C) 2008 Filip Navara +// Copyright (C) 2009-2010 Christoph Frschl +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// - Neither the name of the Xiph.org Foundation nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +using System; + +namespace NSpeex +{ + /// + /// Long Term Prediction Quantisation and Unquantisation (3Tap) + /// + internal class Ltp3Tap : Ltp + { + private float[] gain; + private int[] gain_cdbk; + private int gain_bits; + private int pitch_bits; + private float[][] e; + + public Ltp3Tap(int[] gain_cdbk_0, int gain_bits_1, int pitch_bits_2) + { + this.gain = new float[3]; + this.gain_cdbk = gain_cdbk_0; + this.gain_bits = gain_bits_1; + this.pitch_bits = pitch_bits_2; + this.e = CreateJaggedArray(3, 128); + } + + private T[][] CreateJaggedArray(int dim1, int dim2) + { + T[][] a1 = new T[dim1][]; + for (int i = 0; i < dim1; i++) + { + a1[i] = new T[dim2]; + Array.Clear(a1[i], 0, dim2); + } + return a1; + } + + /// + /// Long Term Prediction Quantification (3Tap). + /// + /// pitch + public sealed override int Quant( + float[] target, float[] sw, int sws, float[] ak, + float[] awk1, float[] awk2, float[] exc, int es, int start, + int end, float pitch_coef, int p, int nsf, Bits bits, float[] exc2, + int e2s, float[] r, int complexity) + { + int i, j; + int[] cdbk_index = new int[1]; + int pitch = 0, best_gain_index = 0; + float[] best_exc; + int best_pitch = 0; + float err, best_err = -1; + int N; + int[] nbest; + float[] gains; + + N = complexity; + if (N > 10) + N = 10; + + nbest = new int[N]; + gains = new float[N]; + + if (N == 0 || end < start) + { + bits.Pack(0, pitch_bits); + bits.Pack(0, gain_bits); + for (i = 0; i < nsf; i++) + exc[es + i] = 0; + return start; + } + + best_exc = new float[nsf]; + + if (N > end - start + 1) + N = end - start + 1; + NSpeex.Ltp.Open_loop_nbest_pitch(sw, sws, start, end, nsf, nbest, gains, N); + + for (i = 0; i < N; i++) + { + pitch = nbest[i]; + for (j = 0; j < nsf; j++) + exc[es + j] = 0; + err = Pitch_gain_search_3tap(target, ak, awk1, awk2, exc, es, + pitch, p, nsf, bits, exc2, e2s, r, cdbk_index); + if (err < best_err || best_err < 0) + { + for (j = 0; j < nsf; j++) + best_exc[j] = exc[es + j]; + best_err = err; + best_pitch = pitch; + best_gain_index = cdbk_index[0]; + } + } + + bits.Pack(best_pitch - start, pitch_bits); + bits.Pack(best_gain_index, gain_bits); + for (i = 0; i < nsf; i++) + exc[es + i] = best_exc[i]; + + return pitch; + } + + /// + /// Long Term Prediction Unquantification (3Tap). + /// + /// pitch + public sealed override int Unquant( + float[] exc, int es, int start, float pitch_coef, + int nsf, float[] gain_val, Bits bits, int count_lost, + int subframe_offset, float last_pitch_gain) + { + int i, pitch, gain_index; + + pitch = bits.Unpack(pitch_bits); + pitch += start; + gain_index = bits.Unpack(gain_bits); + + gain[0] = 0.015625f * (float)gain_cdbk[gain_index * 3] + .5f; + gain[1] = 0.015625f * (float)gain_cdbk[gain_index * 3 + 1] + .5f; + gain[2] = 0.015625f * (float)gain_cdbk[gain_index * 3 + 2] + .5f; + + if (count_lost != 0 && pitch > subframe_offset) + { + float gain_sum = Math.Abs(gain[1]); + float tmp = (count_lost < 4) ? last_pitch_gain + : 0.4f * last_pitch_gain; + if (tmp > .95f) + tmp = .95f; + if (gain[0] > 0) + gain_sum += gain[0]; + else + gain_sum -= .5f * gain[0]; + if (gain[2] > 0) + gain_sum += gain[2]; + else + gain_sum -= .5f * gain[0]; + if (gain_sum > tmp) + { + float fact = tmp / gain_sum; + for (i = 0; i < 3; i++) + gain[i] *= fact; + } + } + + gain_val[0] = gain[0]; + gain_val[1] = gain[1]; + gain_val[2] = gain[2]; + + for (i = 0; i < 3; i++) + { + int j, tmp1, tmp2, pp = pitch + 1 - i; + + tmp1 = nsf; + if (tmp1 > pp) + tmp1 = pp; + tmp2 = nsf; + if (tmp2 > pp + pitch) + tmp2 = pp + pitch; + + for (j = 0; j < tmp1; j++) + e[i][j] = exc[es + j - pp]; + for (j = tmp1; j < tmp2; j++) + e[i][j] = exc[es + j - pp - pitch]; + for (j = tmp2; j < nsf; j++) + e[i][j] = 0; + } + + for (i = 0; i < nsf; i++) + { + exc[es + i] = gain[0] * e[2][i] + gain[1] * e[1][i] + gain[2] + * e[0][i]; + } + + return pitch; + } + + /// + /// Finds the best quantized 3-tap pitch predictor by analysis by synthesis. + /// + /// Target vector + /// LPCs for this subframe + /// Weighted LPCs #1 for this subframe + /// Weighted LPCs #2 for this subframe + /// Excitation + /// + /// Pitch value + /// Number of LPC coeffs + /// Number of samples in subframe + /// + /// + /// + /// + /// + /// the best quantized 3-tap pitch predictor by analysis by + private float Pitch_gain_search_3tap(float[] target, + float[] ak, float[] awk1, float[] awk2, + float[] exc, int es, int pitch, int p, + int nsf, Bits bits, float[] exc2, int e2s, + float[] r, int[] cdbk_index) + { + int i, j; + float[][] x; + // float[][] e; + float[] corr = new float[3]; + float[][] A = CreateJaggedArray(3, 3); + int gain_cdbk_size; + float err1, err2; + + gain_cdbk_size = 1 << gain_bits; + + x = CreateJaggedArray(3, nsf); + e = CreateJaggedArray(3, nsf); + + for (i = 2; i >= 0; i--) + { + int pp = pitch + 1 - i; + for (j = 0; j < nsf; j++) + { + if (j - pp < 0) + e[i][j] = exc2[e2s + j - pp]; + else if (j - pp - pitch < 0) + e[i][j] = exc2[e2s + j - pp - pitch]; + else + e[i][j] = 0; + } + + if (i == 2) + NSpeex.Filters.Syn_percep_zero(e[i], 0, ak, awk1, awk2, x[i], + nsf, p); + else + { + for (j = 0; j < nsf - 1; j++) + x[i][j + 1] = x[i + 1][j]; + x[i][0] = 0; + for (j = 0; j < nsf; j++) + x[i][j] += e[i][0] * r[j]; + } + } + + for (i = 0; i < 3; i++) + corr[i] = NSpeex.Ltp.Inner_prod(x[i], 0, target, 0, nsf); + + for (i = 0; i < 3; i++) + for (j = 0; j <= i; j++) + A[i][j] = A[j][i] = NSpeex.Ltp.Inner_prod(x[i], 0, x[j], 0, nsf); + + { + float[] C = new float[9]; + int ptr = 0; + int best_cdbk = 0; + float best_sum = 0; + C[0] = corr[2]; + C[1] = corr[1]; + C[2] = corr[0]; + C[3] = A[1][2]; + C[4] = A[0][1]; + C[5] = A[0][2]; + C[6] = A[2][2]; + C[7] = A[1][1]; + C[8] = A[0][0]; + + for (i = 0; i < gain_cdbk_size; i++) + { + float sum = 0; + float g0, g1, g2; + ptr = 3 * i; + g0 = 0.015625f * gain_cdbk[ptr] + .5f; + g1 = 0.015625f * gain_cdbk[ptr + 1] + .5f; + g2 = 0.015625f * gain_cdbk[ptr + 2] + .5f; + + sum += C[0] * g0; + sum += C[1] * g1; + sum += C[2] * g2; + sum -= C[3] * g0 * g1; + sum -= C[4] * g2 * g1; + sum -= C[5] * g2 * g0; + sum -= .5f * C[6] * g0 * g0; + sum -= .5f * C[7] * g1 * g1; + sum -= .5f * C[8] * g2 * g2; + + /* + * If true, force "safe" pitch values to handle packet loss + * better + */ + if (false) + { + float tot = Math.Abs(gain_cdbk[ptr + 1]); + if (gain_cdbk[ptr] > 0) + tot += gain_cdbk[ptr]; + if (gain_cdbk[ptr + 2] > 0) + tot += gain_cdbk[ptr + 2]; + if (tot > 1) + continue; + } + + if (sum > best_sum || i == 0) + { + best_sum = sum; + best_cdbk = i; + } + } + gain[0] = 0.015625f * gain_cdbk[best_cdbk * 3] + .5f; + gain[1] = 0.015625f * gain_cdbk[best_cdbk * 3 + 1] + .5f; + gain[2] = 0.015625f * gain_cdbk[best_cdbk * 3 + 2] + .5f; + + cdbk_index[0] = best_cdbk; + } + + for (i = 0; i < nsf; i++) + exc[es + i] = gain[0] * e[2][i] + gain[1] * e[1][i] + gain[2] + * e[0][i]; + + err1 = 0; + err2 = 0; + for (i = 0; i < nsf; i++) + err1 += target[i] * target[i]; + for (i = 0; i < nsf; i++) + err2 += (target[i] - gain[2] * x[0][i] - gain[1] * x[1][i] - gain[0] + * x[2][i]) + * (target[i] - gain[2] * x[0][i] - gain[1] * x[1][i] - gain[0] + * x[2][i]); + + return err2; + } + } +} diff --git a/Assets/Scripts/OpenTS2/NSpeex/Ltp3Tap.cs.meta b/Assets/Scripts/OpenTS2/NSpeex/Ltp3Tap.cs.meta new file mode 100644 index 00000000..f8797f93 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/Ltp3Tap.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0eeb6d6145b0d224fa577f2fd59b2de4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/NSpeex/LtpForcedPitch.cs b/Assets/Scripts/OpenTS2/NSpeex/LtpForcedPitch.cs new file mode 100644 index 00000000..58c709e3 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/LtpForcedPitch.cs @@ -0,0 +1,84 @@ +// +// Copyright (C) 2003 Jean-Marc Valin +// Copyright (C) 1999-2003 Wimba S.A., All Rights Reserved. +// Copyright (C) 2008 Filip Navara +// Copyright (C) 2009-2010 Christoph Frschl +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// - Neither the name of the Xiph.org Foundation nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +namespace NSpeex +{ + /// + /// Long Term Prediction Quantisation and Unquantisation (Forced Pitch) + /// + internal class LtpForcedPitch : Ltp + { + /// + /// Long Term Prediction Quantification (Forced Pitch). + /// + /// pitch + public sealed override int Quant( + float[] target, float[] sw, int sws, float[] ak, + float[] awk1, float[] awk2, float[] exc, int es, int start, + int end, float pitch_coef, int p, int nsf, Bits bits, float[] exc2, + int e2s, float[] r, int complexity) + { + int i; + if (pitch_coef > .99f) + pitch_coef = .99f; + for (i = 0; i < nsf; i++) + { + exc[es + i] = exc[es + i - start] * pitch_coef; + } + return start; + } + + /// + /// Long Term Prediction Unquantification (Forced Pitch). + /// + /// pitch + public sealed override int Unquant(float[] exc, int es, int start, float pitch_coef, + int nsf, float[] gain_val, Bits bits, int count_lost, + int subframe_offset, float last_pitch_gain) + { + int i; + if (pitch_coef > .99f) + { + pitch_coef = .99f; + } + for (i = 0; i < nsf; i++) + { + exc[es + i] = exc[es + i - start] * pitch_coef; + } + gain_val[0] = gain_val[2] = 0; + gain_val[1] = pitch_coef; + return start; + } + } +} diff --git a/Assets/Scripts/OpenTS2/NSpeex/LtpForcedPitch.cs.meta b/Assets/Scripts/OpenTS2/NSpeex/LtpForcedPitch.cs.meta new file mode 100644 index 00000000..971304e8 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/LtpForcedPitch.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0e1ac5a3596f5c342b1d9fbdbcd40ff1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/NSpeex/Misc.cs b/Assets/Scripts/OpenTS2/NSpeex/Misc.cs new file mode 100644 index 00000000..80880769 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/Misc.cs @@ -0,0 +1,77 @@ +// +// Copyright (C) 2003 Jean-Marc Valin +// Copyright (C) 1999-2003 Wimba S.A., All Rights Reserved. +// Copyright (C) 2008 Filip Navara +// Copyright (C) 2009-2010 Christoph Frschl +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// - Neither the name of the Xiph.org Foundation nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +using System; + +namespace NSpeex +{ + /// + /// Miscellaneous functions + /// + internal class Misc + { + /// + /// Builds an Asymmetric "pseudo-Hamming" window. + /// + /// an Asymmetric "pseudo-Hamming" window. + public static float[] Window(int windowSize, int subFrameSize) + { + int i; + int part1 = subFrameSize * 7 / 2; + int part2 = subFrameSize * 5 / 2; + float[] window = new float[windowSize]; + for (i = 0; i < part1; i++) + window[i] = (float)(0.54d - 0.46d * System.Math + .Cos(System.Math.PI * i / part1)); + for (i = 0; i < part2; i++) + window[part1 + i] = (float)(0.54d + 0.46d * System.Math + .Cos(System.Math.PI * i / part2)); + return window; + } + + /// + /// Create the window for autocorrelation (lag-windowing). + /// + /// the window for autocorrelation. + public static float[] LagWindow(int lpcSize, float lagFactor) + { + float[] lagWindow = new float[lpcSize + 1]; + for (int i = 0; i < lpcSize + 1; i++) + lagWindow[i] = (float)Math.Exp(-0.5d + * (2 * System.Math.PI * lagFactor * i) + * (2 * System.Math.PI * lagFactor * i)); + return lagWindow; + } + } +} diff --git a/Assets/Scripts/OpenTS2/NSpeex/Misc.cs.meta b/Assets/Scripts/OpenTS2/NSpeex/Misc.cs.meta new file mode 100644 index 00000000..95c0317b --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/Misc.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2130408c31df0ee439c513e3a197be18 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/NSpeex/NbCodec.cs b/Assets/Scripts/OpenTS2/NSpeex/NbCodec.cs new file mode 100644 index 00000000..57c95bba --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/NbCodec.cs @@ -0,0 +1,386 @@ +// +// Copyright (C) 2003 Jean-Marc Valin +// Copyright (C) 1999-2003 Wimba S.A., All Rights Reserved. +// Copyright (C) 2008 Filip Navara +// Copyright (C) 2009-2010 Christoph Frschl +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// - Neither the name of the Xiph.org Foundation nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +namespace NSpeex +{ + /// + /// Narrowband Codec. This class contains all the basic structures needed by the + /// Narrowband encoder and decoder. + /// + internal class NbCodec + { + #region Constants + + /// + /// Very small initial value for some of the buffers. + /// + protected const float VERY_SMALL = (float)0e-30d; + + /// + /// The Narrowband Frame Size gives the size in bits of a Narrowband frame + /// for a given narrowband submode. + /// + protected static readonly int[] NB_FRAME_SIZE = { 5, 43, 119, 160, 220, 300, 364, + 492, 79, 1, 1, 1, 1, 1, 1, 1 }; + + /// + /// The Narrowband Submodes gives the number of submodes possible for the + /// Narrowband codec. + /// + protected const int NB_SUBMODES = 16; + + /// + /// The Narrowband Submodes Bits gives the number bits used to encode the + /// Narrowband Submode + /// + protected const int NB_SUBMODE_BITS = 4; + protected static readonly float[] exc_gain_quant_scal1 = { -0.35f, 0.05f }; + protected static readonly float[] exc_gain_quant_scal3 = { -2.794750f, + -1.810660f, -1.169850f, -0.848119f, -0.587190f, -0.329818f, + -0.063266f, 0.282826f }; + + #endregion + + #region Tools + + protected internal Lsp m_lsp; + protected internal Filters filters; + + #endregion + + #region Parameters + + /// + /// Sub-mode data + /// + protected internal SubMode[] submodes; + + /// + /// Activated sub-mode + /// + protected internal int submodeID; + + /// + /// Is this the first frame? + /// + protected internal int first; + + /// + /// Size of frames + /// + protected internal int frameSize; + + /// + /// Size of sub-frames + /// + protected internal int subframeSize; + + /// + /// Number of sub-frames + /// + protected internal int nbSubframes; + + /// + /// Analysis (LPC) window length + /// + protected internal int windowSize; + + /// + /// LPC order + /// + protected internal int lpcSize; + + /// + /// Buffer size + /// + protected internal int bufSize; + + /// + /// Minimum pitch value allowed + /// + protected internal int min_pitch; + + /// + /// Maximum pitch value allowed + /// + protected internal int max_pitch; + + /// + /// Perceptual filter: A(z/gamma1) + /// + protected internal float gamma1; + + /// + /// Perceptual filter: A(z/gamma2) + /// + protected internal float gamma2; + + /// + /// Lag windowing Gaussian width + /// + protected internal float lag_factor; + + /// + /// Noise floor multiplier for A[0] in LPC analysis + /// + protected internal float lpc_floor; + + /// + /// Pre-emphasis: P(z) = 1 - a*z^-1 + /// + protected internal float preemph; + + /// + /// 1-element memory for pre-emphasis + /// + protected internal float pre_mem; + + #endregion + + #region Variables + + /// + /// Input buffer (original signal) + /// + protected internal float[] frmBuf; + + protected internal int frmIdx; + + /// + /// Excitation buffer + /// + protected internal float[] excBuf; + + /// + /// Start of excitation frame + /// + protected internal int excIdx; + + /// + /// Innovation for the frame + /// + protected internal float[] innov; + + /// + /// LPCs for current frame + /// + protected internal float[] lpc; + + /// + /// Quantized LSPs for current frame + /// + protected internal float[] qlsp; + + /// + /// Quantized LSPs for previous frame + /// + protected internal float[] old_qlsp; + + /// + /// Interpolated quantized LSPs + /// + protected internal float[] interp_qlsp; + + /// + /// Interpolated quantized LPCs + /// + protected internal float[] interp_qlpc; + + /// + /// Filter memory for synthesis signal + /// + protected internal float[] mem_sp; + + /// + /// Gain of LPC filter at theta=pi (fe/2) + /// + protected internal float[] pi_gain; + protected internal float[] awk1, awk2, awk3; + + // Vocoder data + protected internal float voc_m1; + protected internal float voc_m2; + protected internal float voc_mean; + protected internal int voc_offset; + + /** 1 for enabling DTX, 0 otherwise */ + protected internal int dtx_enabled; + + #endregion + + public NbCodec() + { + m_lsp = new Lsp(); + filters = new Filters(); + Nbinit(); + } + + /// + /// Narrowband initialisation. + /// + private void Nbinit() + { + // Initialize SubModes + submodes = BuildNbSubModes(); + submodeID = 5; + // Initialize narrwoband parameters and variables + Init(160, 40, 10, 640); + } + + /// + /// Initialisation. + /// + protected virtual void Init( + int frameSize, int subframeSize, + int lpcSize, int bufSize) + { + first = 1; + // Codec parameters, should eventually have several "modes" + this.frameSize = frameSize; + this.windowSize = frameSize * 3 / 2; + this.subframeSize = subframeSize; + this.nbSubframes = frameSize / subframeSize; + this.lpcSize = lpcSize; + this.bufSize = bufSize; + min_pitch = 17; + max_pitch = 144; + preemph = 0.0f; + pre_mem = 0.0f; + gamma1 = 0.9f; + gamma2 = 0.6f; + lag_factor = .01f; + lpc_floor = 1.0001f; + + frmBuf = new float[bufSize]; + frmIdx = bufSize - windowSize; + excBuf = new float[bufSize]; + excIdx = bufSize - windowSize; + innov = new float[frameSize]; + + lpc = new float[lpcSize + 1]; + qlsp = new float[lpcSize]; + old_qlsp = new float[lpcSize]; + interp_qlsp = new float[lpcSize]; + interp_qlpc = new float[lpcSize + 1]; + mem_sp = new float[5 * lpcSize]; // TODO - check why 5 (why not 2 or 1) + pi_gain = new float[nbSubframes]; + + awk1 = new float[lpcSize + 1]; + awk2 = new float[lpcSize + 1]; + awk3 = new float[lpcSize + 1]; + + voc_m1 = voc_m2 = voc_mean = 0; + voc_offset = 0; + dtx_enabled = 0; // disabled by default + } + + /// + /// Build narrowband submodes + /// + private static SubMode[] BuildNbSubModes() + { + // Initialize Long Term Predictions + Ltp3Tap ltpNb = new Ltp3Tap(NSpeex.Codebook_Constants.gain_cdbk_nb, 7, 7); + Ltp3Tap ltpVlbr = new Ltp3Tap(NSpeex.Codebook_Constants.gain_cdbk_lbr, 5, 0); + Ltp3Tap ltpLbr = new Ltp3Tap(NSpeex.Codebook_Constants.gain_cdbk_lbr, 5, 7); + Ltp3Tap ltpMed = new Ltp3Tap(NSpeex.Codebook_Constants.gain_cdbk_lbr, 5, 7); + LtpForcedPitch ltpFP = new LtpForcedPitch(); + // Initialize Codebook Searches + NoiseSearch noiseSearch = new NoiseSearch(); + SplitShapeSearch ssNbVlbrSearch = new SplitShapeSearch(40, 10, 4, NSpeex.Codebook_Constants.exc_10_16_table, 4, 0); + SplitShapeSearch ssNbLbrSearch = new SplitShapeSearch(40, 10, 4, NSpeex.Codebook_Constants.exc_10_32_table, 5, 0); + SplitShapeSearch ssNbSearch = new SplitShapeSearch(40, 5, 8, NSpeex.Codebook_Constants.exc_5_64_table, 6, 0); + SplitShapeSearch ssNbMedSearch = new SplitShapeSearch(40, 8, 5, NSpeex.Codebook_Constants.exc_8_128_table, 7, 0); + SplitShapeSearch ssSbSearch = new SplitShapeSearch(40, 5, 8, NSpeex.Codebook_Constants.exc_5_256_table, 8, 0); + SplitShapeSearch ssNbUlbrSearch = new SplitShapeSearch(40, 20, 2, NSpeex.Codebook_Constants.exc_20_32_table, 5, 0); + // Initialize Line Spectral Pair Quantizers + NbLspQuant nbLspQuant = new NbLspQuant(); + LbrLspQuant lbrLspQuant = new LbrLspQuant(); + // Initialize narrow-band modes + SubMode[] nbSubModes = new SubMode[NB_SUBMODES]; + // 2150 bps "vocoder-like" mode for comfort noise + nbSubModes[1] = new SubMode(0, 1, 0, 0, lbrLspQuant, ltpFP, noiseSearch, .7f, .7f, -1, 43); + // 5.95 kbps very low bit-rate mode + nbSubModes[2] = new SubMode(0, 0, 0, 0, lbrLspQuant, ltpVlbr, ssNbVlbrSearch, 0.7f, 0.5f, .55f, 119); + // 8 kbps low bit-rate mode + nbSubModes[3] = new SubMode(-1, 0, 1, 0, lbrLspQuant, ltpLbr, ssNbLbrSearch, 0.7f, 0.55f, .45f, 160); + // 11 kbps medium bit-rate mode + nbSubModes[4] = new SubMode(-1, 0, 1, 0, lbrLspQuant, ltpMed, ssNbMedSearch, 0.7f, 0.63f, .35f, 220); + // 15 kbps high bit-rate mode + nbSubModes[5] = new SubMode(-1, 0, 3, 0, nbLspQuant, ltpNb, ssNbSearch, 0.7f, 0.65f, .25f, 300); + // 18.2 high bit-rate mode + nbSubModes[6] = new SubMode(-1, 0, 3, 0, nbLspQuant, ltpNb, ssSbSearch, 0.68f, 0.65f, .1f, 364); + // 24.6 kbps high bit-rate mode + nbSubModes[7] = new SubMode(-1, 0, 3, 1, nbLspQuant, ltpNb, ssNbSearch, 0.65f, 0.65f, -1, 492); + // 3.95 kbps very low bit-rate mode + nbSubModes[8] = new SubMode(0, 1, 0, 0, lbrLspQuant, ltpFP, ssNbUlbrSearch, .7f, .5f, .65f, 79); + // Return the Narrowband SubModes + return nbSubModes; + } + + public virtual int FrameSize + { + get + { + return frameSize; + } + } + + public float[] PiGain + { + get + { + return pi_gain; + } + } + + public virtual float[] Exc + { + get + { + float[] excTmp = new float[frameSize]; + System.Array.Copy(excBuf, excIdx, excTmp, 0, frameSize); + return excTmp; + } + } + + public virtual float[] Innov + { + get + { + return innov; + } + } + } +} diff --git a/Assets/Scripts/OpenTS2/NSpeex/NbCodec.cs.meta b/Assets/Scripts/OpenTS2/NSpeex/NbCodec.cs.meta new file mode 100644 index 00000000..dda3f20f --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/NbCodec.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: cc9b63b26b4b29444b26f4a41820f70d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/NSpeex/NbDecoder.cs b/Assets/Scripts/OpenTS2/NSpeex/NbDecoder.cs new file mode 100644 index 00000000..50a1c663 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/NbDecoder.cs @@ -0,0 +1,701 @@ +// +// Copyright (C) 2003 Jean-Marc Valin +// Copyright (C) 1999-2003 Wimba S.A., All Rights Reserved. +// Copyright (C) 2008 Filip Navara +// Copyright (C) 2009-2010 Christoph Frschl +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// - Neither the name of the Xiph.org Foundation nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +using System; +using System.IO; + +namespace NSpeex +{ + /// + /// Narrowband Speex Decoder + /// + internal class NbDecoder : NbCodec, IDecoder + { + private float[] innov2; + + /// + /// Packet loss + /// + private int count_lost; + + /// + /// Pitch of last correctly decoded frame + /// + private int last_pitch; + + /// + /// Pitch gain of last correctly decoded frame + /// + private float last_pitch_gain; + + /// + /// Pitch gain of last decoded frames + /// + private float[] pitch_gain_buf; + + /// + /// Tail of the buffer + /// + private int pitch_gain_buf_idx; + + /// + /// Open-loop gain for previous frame + /// + private float last_ol_gain; + + protected internal Random random; + protected internal Stereo stereo; + protected internal Inband inband; + protected internal bool enhanced; + + public NbDecoder() + { + this.random = new Random(); + stereo = new Stereo(); + inband = new Inband(stereo); + enhanced = true; + } + + protected override void Init(int frameSize, int subframeSize, int lpcSize, int bufSize) + { + base.Init(frameSize, subframeSize, lpcSize, bufSize); + innov2 = new float[40]; + + count_lost = 0; + last_pitch = 40; + last_pitch_gain = 0; + pitch_gain_buf = new float[3]; + pitch_gain_buf_idx = 0; + last_ol_gain = 0; + } + + /// + /// Decode the given input bits. + /// + /// 1 if a terminator was found, 0 if not. + /// If there is an error detected in the data stream. + public virtual int Decode(Bits bits, float[] xout) + { + int i, sub, pitch, ol_pitch = 0, m; + float[] pitch_gain = new float[3]; + float ol_gain = 0.0f, ol_pitch_coef = 0.0f; + int best_pitch = 40; + float best_pitch_gain = 0; + float pitch_average = 0; + + if (bits == null && dtx_enabled != 0) + { + submodeID = 0; + } + else + { + /* + * If bits is NULL, consider the packet to be lost (what could we do + * anyway) + */ + if (bits == null) + { + DecodeLost(xout); + return 0; + } + /* + * Search for next narrowband block (handle requests, skip wideband + * blocks) + */ + do + { + if (bits.BitsRemaining() < 5) + return -1; + + if (bits.Unpack(1) != 0) + { /* + * Skip wideband block (for + * compatibility) + */ + // Wideband + /* Get the sub-mode that was used */ + m = bits.Unpack(NSpeex.SbCodec.SB_SUBMODE_BITS); + int advance = NSpeex.SbCodec.SB_FRAME_SIZE[m]; + if (advance < 0) + { + throw new InvalidFormatException( + "Invalid sideband mode encountered (1st sideband): " + + m); + // return -2; + } + advance -= (NSpeex.SbCodec.SB_SUBMODE_BITS + 1); + bits.Advance(advance); + if (bits.Unpack(1) != 0) + { /* + * Skip ultra-wideband block + * (for compatibility) + */ + /* Get the sub-mode that was used */ + m = bits.Unpack(NSpeex.SbCodec.SB_SUBMODE_BITS); + advance = NSpeex.SbCodec.SB_FRAME_SIZE[m]; + if (advance < 0) + { + throw new InvalidFormatException( + "Invalid sideband mode encountered. (2nd sideband): " + + m); + // return -2; + } + advance -= (NSpeex.SbCodec.SB_SUBMODE_BITS + 1); + bits.Advance(advance); + if (bits.Unpack(1) != 0) + { /* Sanity check */ + throw new InvalidFormatException( + "More than two sideband layers found"); + // return -2; + } + } + // */ + } + + if (bits.BitsRemaining() < 4) + return 1; + + /* Get the sub-mode that was used */ + m = bits.Unpack(NSpeex.NbCodec.NB_SUBMODE_BITS); + if (m == 15) + { /* We found a terminator */ + return 1; + } + else if (m == 14) + { /* Speex in-band request */ + inband.SpeexInbandRequest(bits); + } + else if (m == 13) + { /* User in-band request */ + inband.UserInbandRequest(bits); + } + else if (m > 8) + { /* Invalid mode */ + throw new InvalidFormatException( + "Invalid mode encountered: " + m); + // return -2; + } + } while (m > 8); + submodeID = m; + } + + /* Shift all buffers by one frame */ + System.Array.Copy(frmBuf, frameSize, frmBuf, 0, bufSize + - frameSize); + System.Array.Copy(excBuf, frameSize, excBuf, 0, bufSize + - frameSize); + + /* If null mode (no transmission), just set a couple things to zero */ + if (submodes[submodeID] == null) + { + NSpeex.Filters.Bw_lpc(.93f, interp_qlpc, lpc, 10); + + float innov_gain = 0; + for (i = 0; i < frameSize; i++) + innov_gain += innov[i] * innov[i]; + innov_gain = (float)Math.Sqrt(innov_gain / frameSize); + for (i = excIdx; i < excIdx + frameSize; i++) + { + excBuf[i] = (float)(3 * innov_gain * (random.NextDouble() - .5f)); + } + first = 1; + + /* Final signal synthesis from excitation */ + NSpeex.Filters.Iir_mem2(excBuf, excIdx, lpc, frmBuf, frmIdx, + frameSize, lpcSize, mem_sp); + + xout[0] = frmBuf[frmIdx] + preemph * pre_mem; + for (i = 1; i < frameSize; i++) + xout[i] = frmBuf[frmIdx + i] + preemph * xout[i - 1]; + pre_mem = xout[frameSize - 1]; + count_lost = 0; + return 0; + } + + /* Unquantize LSPs */ + submodes[submodeID].LsqQuant.Unquant(qlsp, lpcSize, bits); + + /* Damp memory if a frame was lost and the LSP changed too much */ + if (count_lost != 0) + { + float lsp_dist = 0, fact; + for (i = 0; i < lpcSize; i++) + lsp_dist += Math.Abs(old_qlsp[i] - qlsp[i]); + fact = (float)(.6d * Math.Exp(-.2d * lsp_dist)); + for (i = 0; i < 2 * lpcSize; i++) + mem_sp[i] *= fact; + } + + /* Handle first frame and lost-packet case */ + if (first != 0 || count_lost != 0) + { + for (i = 0; i < lpcSize; i++) + old_qlsp[i] = qlsp[i]; + } + + /* Get open-loop pitch estimation for low bit-rate pitch coding */ + if (submodes[submodeID].LbrPitch != -1) + { + ol_pitch = min_pitch + bits.Unpack(7); + } + + if (submodes[submodeID].ForcedPitchGain != 0) + { + int quant = bits.Unpack(4); + ol_pitch_coef = 0.066667f * quant; + } + + /* Get global excitation gain */ + int qe = bits.Unpack(5); + ol_gain = (float)Math.Exp(qe / 3.5d); + + /* unpacks unused dtx bits */ + if (submodeID == 1) + { + int extra = bits.Unpack(4); + if (extra == 15) + dtx_enabled = 1; + else + dtx_enabled = 0; + } + if (submodeID > 1) + dtx_enabled = 0; + + /* Loop on subframes */ + for (sub = 0; sub < nbSubframes; sub++) + { + int offset, spIdx, extIdx; + float tmp; + /* Offset relative to start of frame */ + offset = subframeSize * sub; + /* Original signal */ + spIdx = frmIdx + offset; + /* Excitation */ + extIdx = excIdx + offset; + + /* LSP interpolation (quantized and unquantized) */ + tmp = (1.0f + sub) / nbSubframes; + for (i = 0; i < lpcSize; i++) + interp_qlsp[i] = (1 - tmp) * old_qlsp[i] + tmp * qlsp[i]; + + /* Make sure the LSP's are stable */ + NSpeex.Lsp.Enforce_margin(interp_qlsp, lpcSize, .002f); + + /* Compute interpolated LPCs (unquantized) */ + for (i = 0; i < lpcSize; i++) + interp_qlsp[i] = (float)System.Math.Cos(interp_qlsp[i]); + m_lsp.Lsp2lpc(interp_qlsp, interp_qlpc, lpcSize); + + /* Compute enhanced synthesis filter */ + if (enhanced) + { + float r = .9f; + float k1, k2, k3; + + k1 = submodes[submodeID].LpcEnhK1; + k2 = submodes[submodeID].LpcEnhK2; + k3 = (1 - (1 - r * k1) / (1 - r * k2)) / r; + NSpeex.Filters.Bw_lpc(k1, interp_qlpc, awk1, lpcSize); + NSpeex.Filters.Bw_lpc(k2, interp_qlpc, awk2, lpcSize); + NSpeex.Filters.Bw_lpc(k3, interp_qlpc, awk3, lpcSize); + } + + /* Compute analysis filter at w=pi */ + tmp = 1; + pi_gain[sub] = 0; + for (i = 0; i <= lpcSize; i++) + { + pi_gain[sub] += tmp * interp_qlpc[i]; + tmp = -tmp; + } + + /* Reset excitation */ + for (i = 0; i < subframeSize; i++) + excBuf[extIdx + i] = 0; + + /* Adaptive codebook contribution */ + int pit_min, pit_max; + + /* Handle pitch constraints if any */ + if (submodes[submodeID].LbrPitch != -1) + { + int margin = submodes[submodeID].LbrPitch; + if (margin != 0) + { + pit_min = ol_pitch - margin + 1; + if (pit_min < min_pitch) + pit_min = min_pitch; + pit_max = ol_pitch + margin; + if (pit_max > max_pitch) + pit_max = max_pitch; + } + else + { + pit_min = pit_max = ol_pitch; + } + } + else + { + pit_min = min_pitch; + pit_max = max_pitch; + } + + /* Pitch synthesis */ + pitch = submodes[submodeID].Ltp.Unquant(excBuf, extIdx, pit_min, + ol_pitch_coef, subframeSize, pitch_gain, bits, count_lost, + offset, last_pitch_gain); + + /* If we had lost frames, check energy of last received frame */ + if (count_lost != 0 && ol_gain < last_ol_gain) + { + float fact_0 = ol_gain / (last_ol_gain + 1); + for (i = 0; i < subframeSize; i++) + excBuf[excIdx + i] *= fact_0; + } + + tmp = Math.Abs(pitch_gain[0] + pitch_gain[1] + + pitch_gain[2]); + tmp = Math.Abs(pitch_gain[1]); + if (pitch_gain[0] > 0) + tmp += pitch_gain[0]; + else + tmp -= .5f * pitch_gain[0]; + if (pitch_gain[2] > 0) + tmp += pitch_gain[2]; + else + tmp -= .5f * pitch_gain[0]; + + pitch_average += tmp; + if (tmp > best_pitch_gain) + { + best_pitch = pitch; + best_pitch_gain = tmp; + } + + /* Unquantize the innovation */ + int q_energy, ivi = sub * subframeSize; + float ener; + + for (i = ivi; i < ivi + subframeSize; i++) + innov[i] = 0.0f; + + /* Decode sub-frame gain correction */ + if (submodes[submodeID].HaveSubframeGain == 3) + { + q_energy = bits.Unpack(3); + ener = (float)(ol_gain * Math.Exp(NSpeex.NbCodec.exc_gain_quant_scal3[q_energy])); + } + else if (submodes[submodeID].HaveSubframeGain == 1) + { + q_energy = bits.Unpack(1); + ener = (float)(ol_gain * Math.Exp(NSpeex.NbCodec.exc_gain_quant_scal1[q_energy])); + } + else + { + ener = ol_gain; + } + + if (submodes[submodeID].Innovation != null) + { + /* Fixed codebook contribution */ + submodes[submodeID].Innovation.Unquantify(innov, ivi, + subframeSize, bits); + } + + /* De-normalize innovation and update excitation */ + for (i = ivi; i < ivi + subframeSize; i++) + innov[i] *= ener; + + /* Vocoder mode */ + if (submodeID == 1) + { + float g = ol_pitch_coef; + + for (i = 0; i < subframeSize; i++) + excBuf[extIdx + i] = 0; + while (voc_offset < subframeSize) + { + if (voc_offset >= 0) + excBuf[extIdx + voc_offset] = (float)Math.Sqrt(1.0f * ol_pitch); + voc_offset += ol_pitch; + } + voc_offset -= subframeSize; + + g = .5f + 2 * (g - .6f); + if (g < 0) + g = 0; + if (g > 1) + g = 1; + for (i = 0; i < subframeSize; i++) + { + float itmp = excBuf[extIdx + i]; + excBuf[extIdx + i] = .8f * g * excBuf[extIdx + i] * ol_gain + + .6f * g * voc_m1 * ol_gain + .5f * g + * innov[ivi + i] - .5f * g * voc_m2 + (1 - g) + * innov[ivi + i]; + voc_m1 = itmp; + voc_m2 = innov[ivi + i]; + voc_mean = .95f * voc_mean + .05f * excBuf[extIdx + i]; + excBuf[extIdx + i] -= voc_mean; + } + } + else + { + for (i = 0; i < subframeSize; i++) + excBuf[extIdx + i] += innov[ivi + i]; + } + + /* Decode second codebook (only for some modes) */ + if (submodes[submodeID].DoubleCodebook != 0) + { + for (i = 0; i < subframeSize; i++) + innov2[i] = 0; + submodes[submodeID].Innovation.Unquantify(innov2, 0, subframeSize, + bits); + for (i = 0; i < subframeSize; i++) + innov2[i] *= ener * (1 / 2.2f); + for (i = 0; i < subframeSize; i++) + excBuf[extIdx + i] += innov2[i]; + } + + for (i = 0; i < subframeSize; i++) + frmBuf[spIdx + i] = excBuf[extIdx + i]; + + /* Signal synthesis */ + if (enhanced && submodes[submodeID].CombGain > 0) + { + filters.Comb_filter(excBuf, extIdx, frmBuf, spIdx, + subframeSize, pitch, pitch_gain, + submodes[submodeID].CombGain); + } + + if (enhanced) + { + /* Use enhanced LPC filter */ + NSpeex.Filters.Filter_mem2(frmBuf, spIdx, awk2, awk1, + subframeSize, lpcSize, mem_sp, lpcSize); + NSpeex.Filters.Filter_mem2(frmBuf, spIdx, awk3, interp_qlpc, + subframeSize, lpcSize, mem_sp, 0); + } + else + { + /* Use regular filter */ + for (i = 0; i < lpcSize; i++) + mem_sp[lpcSize + i] = 0; + NSpeex.Filters.Iir_mem2(frmBuf, spIdx, interp_qlpc, frmBuf, + spIdx, subframeSize, lpcSize, mem_sp); + } + } + + /* Copy output signal */ + xout[0] = frmBuf[frmIdx] + preemph * pre_mem; + for (i = 1; i < frameSize; i++) + xout[i] = frmBuf[frmIdx + i] + preemph * xout[i - 1]; + pre_mem = xout[frameSize - 1]; + + /* Store the LSPs for interpolation in the next frame */ + for (i = 0; i < lpcSize; i++) + old_qlsp[i] = qlsp[i]; + + /* The next frame will not be the first (Duh!) */ + first = 0; + count_lost = 0; + last_pitch = best_pitch; + last_pitch_gain = .25f * pitch_average; + pitch_gain_buf[pitch_gain_buf_idx++] = last_pitch_gain; + if (pitch_gain_buf_idx > 2) /* rollover */ + pitch_gain_buf_idx = 0; + last_ol_gain = ol_gain; + + return 0; + } + + /// + /// Decode when packets are lost. + /// + /// 0 if successful. + public int DecodeLost(float[] xout) + { + int i; + float pitch_gain, fact, gain_med; + + fact = (float)Math.Exp(-.04d * count_lost * count_lost); + // median3(a, b, c) = (a .95f) + pitch_gain = .95f; + + pitch_gain *= fact; + + /* Shift all buffers by one frame */ + System.Array.Copy(frmBuf, frameSize, frmBuf, 0, bufSize + - frameSize); + System.Array.Copy(excBuf, frameSize, excBuf, 0, bufSize + - frameSize); + + for (int sub = 0; sub < nbSubframes; sub++) + { + int offset; + int spIdx, extIdx; + /* Offset relative to start of frame */ + offset = subframeSize * sub; + /* Original signal */ + spIdx = frmIdx + offset; + /* Excitation */ + extIdx = excIdx + offset; + /* Excitation after post-filter */ + + /* Calculate perceptually enhanced LPC filter */ + if (enhanced) + { + float r = .9f; + float k1, k2, k3; + if (submodes[submodeID] != null) + { + k1 = submodes[submodeID].LpcEnhK1; + k2 = submodes[submodeID].LpcEnhK2; + } + else + { + k1 = k2 = 0.7f; + } + k3 = (1 - (1 - r * k1) / (1 - r * k2)) / r; + NSpeex.Filters.Bw_lpc(k1, interp_qlpc, awk1, lpcSize); + NSpeex.Filters.Bw_lpc(k2, interp_qlpc, awk2, lpcSize); + NSpeex.Filters.Bw_lpc(k3, interp_qlpc, awk3, lpcSize); + } + /* Make up a plausible excitation */ + /* THIS CAN BE IMPROVED */ + /* + * if (pitch_gain>.95) pitch_gain=.95; + */ + { + float innov_gain = 0; + for (i = 0; i < frameSize; i++) + innov_gain += innov[i] * innov[i]; + innov_gain = (float)Math.Sqrt(innov_gain / frameSize); + for (i = 0; i < subframeSize; i++) + { + // #if 0 + // excBuf[extIdx+i] = pitch_gain*excBuf[extIdx+i-last_pitch] + // + fact*((float)Math.sqrt(1-pitch_gain))*innov[i+offset]; + // /*Just so it give the same lost packets as with if 0*/ + // /*rand();*/ + // #else + /* + * excBuf[extIdx+i] = pitch_gain*excBuf[extIdx+i-last_pitch] + + * fact*innov[i+offset]; + */ + excBuf[extIdx + i] = pitch_gain + * excBuf[extIdx + i - last_pitch] + fact + * ((float)Math.Sqrt(1 - pitch_gain)) * 3 + * innov_gain * (((float)random.NextDouble()) - 0.5f); + // #endif + } + } + for (i = 0; i < subframeSize; i++) + frmBuf[spIdx + i] = excBuf[extIdx + i]; + + /* Signal synthesis */ + if (enhanced) + { + /* Use enhanced LPC filter */ + NSpeex.Filters.Filter_mem2(frmBuf, spIdx, awk2, awk1, + subframeSize, lpcSize, mem_sp, lpcSize); + NSpeex.Filters.Filter_mem2(frmBuf, spIdx, awk3, interp_qlpc, + subframeSize, lpcSize, mem_sp, 0); + } + else + { + /* Use regular filter */ + for (i = 0; i < lpcSize; i++) + mem_sp[lpcSize + i] = 0; + NSpeex.Filters.Iir_mem2(frmBuf, spIdx, interp_qlpc, frmBuf, + spIdx, subframeSize, lpcSize, mem_sp); + } + } + + xout[0] = frmBuf[0] + preemph * pre_mem; + for (i = 1; i < frameSize; i++) + xout[i] = frmBuf[i] + preemph * xout[i - 1]; + pre_mem = xout[frameSize - 1]; + first = 0; + count_lost++; + pitch_gain_buf[pitch_gain_buf_idx++] = pitch_gain; + if (pitch_gain_buf_idx > 2) /* rollover */ + pitch_gain_buf_idx = 0; + + return 0; + } + + /// + /// Decode the given bits to stereo. + /// + public virtual void DecodeStereo(float[] data, int frameSize) + { + stereo.Decode(data, frameSize); + } + + public bool Dtx + { + get + { + // TODO - should return DTX for the NbCodec + return dtx_enabled != 0; + } + } + + public virtual bool PerceptualEnhancement + { + get + { + return enhanced; + } + set + { + this.enhanced = value; + } + } + } +} diff --git a/Assets/Scripts/OpenTS2/NSpeex/NbDecoder.cs.meta b/Assets/Scripts/OpenTS2/NSpeex/NbDecoder.cs.meta new file mode 100644 index 00000000..1bdbf7c0 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/NbDecoder.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8753971c77875a44eb92e1ff81a886a2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/NSpeex/NbEncoder.cs b/Assets/Scripts/OpenTS2/NSpeex/NbEncoder.cs new file mode 100644 index 00000000..478c993e --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/NbEncoder.cs @@ -0,0 +1,1139 @@ +// +// Copyright (C) 2003 Jean-Marc Valin +// Copyright (C) 1999-2003 Wimba S.A., All Rights Reserved. +// Copyright (C) 2008 Filip Navara +// Copyright (C) 2009-2010 Christoph Frschl +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// - Neither the name of the Xiph.org Foundation nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +using System; + +namespace NSpeex +{ + /// + /// Narrowband Speex Encoder + /// + internal class NbEncoder : NbCodec, IEncoder + { + /// + /// The Narrowband Quality map indicates which narrowband submode to use for + /// the given narrowband quality setting + /// + public static readonly int[] NB_QUALITY_MAP = { 1, 8, 2, 3, 3, 4, 4, 5, 5, 6, 7 }; + + /// + /// Next frame should not rely on previous frames for pitch + /// + private int bounded_pitch; + private int[] pitch; + + /// + /// 1-element memory for pre-emphasis + /// + private float pre_mem2; + + /// + /// "Pitch enhanced" excitation + /// + private float[] exc2Buf; + + /// + /// "Pitch enhanced" excitation + /// + private int exc2Idx; + + /// + /// Weighted signal buffer + /// + private float[] swBuf; + + /// + /// Start of weighted signal frame + /// + private int swIdx; + + /// + /// Temporary (Hanning) window + /// + private float[] window; + + /// + /// 2nd temporary buffer + /// + private float[] buf2; + + /// + /// auto-correlation + /// + private float[] autocorr; + + /// + /// Window applied to auto-correlation + /// + private float[] lagWindow; + + /// + /// LSPs for current frame + /// + private float[] lsp; + + /// + /// LSPs for previous frame + /// + private float[] old_lsp; + + /// + /// Interpolated LSPs + /// + private float[] interp_lsp; + + /// + /// Interpolated LPCs + /// + private float[] interp_lpc; + + /// + /// LPCs after bandwidth expansion by gamma1 for perceptual weighting + /// + private float[] bw_lpc1; + + /// + /// LPCs after bandwidth expansion by gamma2 for perceptual weighting + /// + private float[] bw_lpc2; + + /// + /// Reflection coefficients + /// + private float[] rc; + + /// + /// Filter memory for perceptually-weighted signal + /// + private float[] mem_sw; + + /// + /// Filter memory for perceptually-weighted signal (whole frame) + /// + private float[] mem_sw_whole; + + /// + /// Filter memory for excitation (whole frame) + /// + private float[] mem_exc; + + /// + /// State of the VBR data + /// + private Vbr vbr; + + /// + /// Number of consecutive DTX frames + /// + private int dtx_count; + + private float[] innov2; + + /// + /// Complexity setting (0-10 from least complex to most complex) + /// + protected internal int complexity; + + /// + /// 1 for enabling VBR, 0 otherwise + /// + protected internal int vbr_enabled; + + /// + /// 1 for enabling VAD, 0 otherwise + /// + protected internal int vad_enabled; + + /// + /// ABR setting (in bps), 0 if off + /// + protected internal int abr_enabled; + + /// + /// Quality setting for VBR encoding + /// + protected internal float vbr_quality; + + /// + /// Relative quality that will be needed by VBR + /// + protected internal float relative_quality; + + protected internal float abr_drift; + protected internal float abr_drift2; + protected internal float abr_count; + protected internal int sampling_rate; + + /// + /// Mode chosen by the user (may differ from submodeID if VAD is on) + /// + protected internal int submodeSelect; + + /// + /// Initialisation + /// + protected override void Init(int frameSize, int subframeSize, int lpcSize, int bufSize) + { + base.Init(frameSize, subframeSize, lpcSize, bufSize); + + complexity = 3; // in C it's 2 here, but set to 3 automatically by the + // encoder + vbr_enabled = 0; // disabled by default + vad_enabled = 0; // disabled by default + abr_enabled = 0; // disabled by default + vbr_quality = 8; + + submodeSelect = 5; + pre_mem2 = 0; + bounded_pitch = 1; + + exc2Buf = new float[bufSize]; + exc2Idx = bufSize - windowSize; + swBuf = new float[bufSize]; + swIdx = bufSize - windowSize; + + window = NSpeex.Misc.Window(windowSize, subframeSize); + lagWindow = NSpeex.Misc.LagWindow(lpcSize, lag_factor); + + autocorr = new float[lpcSize + 1]; + buf2 = new float[windowSize]; + + interp_lpc = new float[lpcSize + 1]; + interp_qlpc = new float[lpcSize + 1]; + bw_lpc1 = new float[lpcSize + 1]; + bw_lpc2 = new float[lpcSize + 1]; + lsp = new float[lpcSize]; + qlsp = new float[lpcSize]; + old_lsp = new float[lpcSize]; + old_qlsp = new float[lpcSize]; + interp_lsp = new float[lpcSize]; + interp_qlsp = new float[lpcSize]; + + rc = new float[lpcSize]; + mem_sp = new float[lpcSize]; // why was there a *5 before ?!? + mem_sw = new float[lpcSize]; + mem_sw_whole = new float[lpcSize]; + mem_exc = new float[lpcSize]; + + vbr = new Vbr(); + dtx_count = 0; + abr_count = 0; + sampling_rate = 8000; + + awk1 = new float[lpcSize + 1]; + awk2 = new float[lpcSize + 1]; + awk3 = new float[lpcSize + 1]; + innov2 = new float[40]; + + pitch = new int[nbSubframes]; + } + + /// + /// Encode the given input signal. + /// + /// return 1 if successful. + public virtual int Encode(Bits bits, float[] ins0) + { + int i; + float[] res, target, mem; + float[] syn_resp; + float[] orig; + + /* Copy new data in input buffer */ + System.Array.Copy(frmBuf, frameSize, frmBuf, 0, bufSize + - frameSize); + frmBuf[bufSize - frameSize] = ins0[0] - preemph * pre_mem; + for (i = 1; i < frameSize; i++) + frmBuf[bufSize - frameSize + i] = ins0[i] - preemph * ins0[i - 1]; + pre_mem = ins0[frameSize - 1]; + + /* Move signals 1 frame towards the past */ + System.Array.Copy(exc2Buf, frameSize, exc2Buf, 0, bufSize + - frameSize); + System.Array.Copy(excBuf, frameSize, excBuf, 0, bufSize + - frameSize); + System.Array.Copy(swBuf, frameSize, swBuf, 0, bufSize + - frameSize); + + /* Window for analysis */ + for (i = 0; i < windowSize; i++) + buf2[i] = frmBuf[i + frmIdx] * window[i]; + + /* Compute auto-correlation */ + NSpeex.Lpc.Autocorr(buf2, autocorr, lpcSize + 1, windowSize); + + autocorr[0] += 10; /* prevents NANs */ + autocorr[0] *= lpc_floor; /* Noise floor in auto-correlation domain */ + + /* Lag windowing: equivalent to filtering in the power-spectrum domain */ + for (i = 0; i < lpcSize + 1; i++) + autocorr[i] *= lagWindow[i]; + + /* Levinson-Durbin */ + NSpeex.Lpc.Wld(lpc, autocorr, rc, lpcSize); // tmperr + System.Array.Copy(lpc, 0, lpc, 1, lpcSize); + lpc[0] = 1; + + /* LPC to LSPs (x-domain) transform */ + int roots = NSpeex.Lsp.Lpc2lsp(lpc, lpcSize, lsp, 15, 0.2f); + /* Check if we found all the roots */ + if (roots == lpcSize) + { + /* LSP x-domain to angle domain */ + for (i = 0; i < lpcSize; i++) + lsp[i] = (float)System.Math.Acos(lsp[i]); + } + else + { + /* Search again if we can afford it */ + if (complexity > 1) + roots = NSpeex.Lsp.Lpc2lsp(lpc, lpcSize, lsp, 11, 0.05f); + if (roots == lpcSize) + { + /* LSP x-domain to angle domain */ + for (i = 0; i < lpcSize; i++) + lsp[i] = (float)System.Math.Acos(lsp[i]); + } + else + { + /* + * If we can't find all LSP's, do some damage control and use + * previous filter + */ + for (i = 0; i < lpcSize; i++) + { + lsp[i] = old_lsp[i]; + } + } + } + + float lsp_dist = 0; + for (i = 0; i < lpcSize; i++) + lsp_dist += (old_lsp[i] - lsp[i]) * (old_lsp[i] - lsp[i]); + + /* + * Whole frame analysis (open-loop estimation of pitch and excitation + * gain) + */ + float ol_gain; + int ol_pitch; + float ol_pitch_coef; + { + if (first != 0) + for (i = 0; i < lpcSize; i++) + interp_lsp[i] = lsp[i]; + else + for (i = 0; i < lpcSize; i++) + interp_lsp[i] = .375f * old_lsp[i] + .625f * lsp[i]; + + NSpeex.Lsp.Enforce_margin(interp_lsp, lpcSize, .002f); + + /* Compute interpolated LPCs (unquantized) for whole frame */ + for (i = 0; i < lpcSize; i++) + interp_lsp[i] = (float)System.Math.Cos(interp_lsp[i]); + m_lsp.Lsp2lpc(interp_lsp, interp_lpc, lpcSize); + + /* Open-loop pitch */ + if (submodes[submodeID] == null || vbr_enabled != 0 + || vad_enabled != 0 + || submodes[submodeID].ForcedPitchGain != 0 + || submodes[submodeID].LbrPitch != -1) + { + int[] nol_pitch = new int[6]; + float[] nol_pitch_coef = new float[6]; + + NSpeex.Filters.Bw_lpc(gamma1, interp_lpc, bw_lpc1, lpcSize); + NSpeex.Filters.Bw_lpc(gamma2, interp_lpc, bw_lpc2, lpcSize); + + NSpeex.Filters.Filter_mem2(frmBuf, frmIdx, bw_lpc1, bw_lpc2, + swBuf, swIdx, frameSize, lpcSize, mem_sw_whole, 0); + + NSpeex.Ltp.Open_loop_nbest_pitch(swBuf, swIdx, min_pitch, + max_pitch, frameSize, nol_pitch, nol_pitch_coef, 6); + ol_pitch = nol_pitch[0]; + ol_pitch_coef = nol_pitch_coef[0]; + /* Try to remove pitch multiples */ + for (i = 1; i < 6; i++) + { + if ((nol_pitch_coef[i] > .85d * ol_pitch_coef) + && (Math.Abs(nol_pitch[i] - ol_pitch + / 2.0d) <= 1 + || Math.Abs(nol_pitch[i] + - ol_pitch / 3.0d) <= 1 + || Math.Abs(nol_pitch[i] + - ol_pitch / 4.0d) <= 1 || Math.Abs(nol_pitch[i] - ol_pitch / 5.0d) <= 1)) + { + /* ol_pitch_coef=nol_pitch_coef[i]; */ + ol_pitch = nol_pitch[i]; + } + } + /* + * if (ol_pitch>50) ol_pitch/=2; + */ + /* ol_pitch_coef = sqrt(ol_pitch_coef); */ + } + else + { + ol_pitch = 0; + ol_pitch_coef = 0; + } + /* Compute "real" excitation */ + NSpeex.Filters.Fir_mem2(frmBuf, frmIdx, interp_lpc, excBuf, excIdx, + frameSize, lpcSize, mem_exc); + + /* Compute open-loop excitation gain */ + ol_gain = 0; + for (i = 0; i < frameSize; i++) + ol_gain += excBuf[excIdx + i] * excBuf[excIdx + i]; + + ol_gain = (float)Math.Sqrt(1 + ol_gain / frameSize); + } + + /* VBR stuff */ + if (vbr != null && (vbr_enabled != 0 || vad_enabled != 0)) + { + if (abr_enabled != 0) + { + float qual_change = 0; + if (abr_drift2 * abr_drift > 0) + { + /* + * Only adapt if long-term and short-term drift are the same + * sign + */ + qual_change = -.00001f * abr_drift / (1 + abr_count); + if (qual_change > .05f) + qual_change = .05f; + if (qual_change < -.05f) + qual_change = -.05f; + } + vbr_quality += qual_change; + if (vbr_quality > 10) + vbr_quality = 10; + if (vbr_quality < 0) + vbr_quality = 0; + } + relative_quality = vbr.Analysis(ins0, frameSize, ol_pitch, + ol_pitch_coef); + /* if (delta_qual<0) */ + /* delta_qual*=.1*(3+st->vbr_quality); */ + if (vbr_enabled != 0) + { + int mode; + int choice = 0; + float min_diff = 100; + mode = 8; + while (mode > 0) + { + int v1; + float thresh; + v1 = (int)Math.Floor(vbr_quality); + if (v1 == 10) + thresh = NSpeex.Vbr.nb_thresh[mode][v1]; + else + thresh = (vbr_quality - v1) + * NSpeex.Vbr.nb_thresh[mode][v1 + 1] + + (1 + v1 - vbr_quality) + * NSpeex.Vbr.nb_thresh[mode][v1]; + if (relative_quality > thresh + && relative_quality - thresh < min_diff) + { + choice = mode; + min_diff = relative_quality - thresh; + } + mode--; + } + mode = choice; + if (mode == 0) + { + if (dtx_count == 0 || lsp_dist > .05d || dtx_enabled == 0 + || dtx_count > 20) + { + mode = 1; + dtx_count = 1; + } + else + { + mode = 0; + dtx_count++; + } + } + else + { + dtx_count = 0; + } + Mode = mode; + + if (abr_enabled != 0) + { + int bitrate; + bitrate = BitRate; + abr_drift += (bitrate - abr_enabled); + abr_drift2 = .95f * abr_drift2 + .05f + * (bitrate - abr_enabled); + abr_count += ((Single?)1.0d).Value; + } + + } + else + { + /* VAD only case */ + int mode_0; + if (relative_quality < 2) + { + if (dtx_count == 0 || lsp_dist > .05d || dtx_enabled == 0 + || dtx_count > 20) + { + dtx_count = 1; + mode_0 = 1; + } + else + { + mode_0 = 0; + dtx_count++; + } + } + else + { + dtx_count = 0; + mode_0 = submodeSelect; + } + /* speex_encoder_ctl(state, SPEEX_SET_MODE, &mode); */ + submodeID = mode_0; + } + } + else + { + relative_quality = -1; + } + + /* First, transmit a zero for narrowband */ + bits.Pack(0, 1); + + /* Transmit the sub-mode we use for this frame */ + bits.Pack(submodeID, NSpeex.NbCodec.NB_SUBMODE_BITS); + + /* If null mode (no transmission), just set a couple things to zero */ + if (submodes[submodeID] == null) + { + for (i = 0; i < frameSize; i++) + excBuf[excIdx + i] = exc2Buf[exc2Idx + i] = swBuf[swIdx + i] = NSpeex.NbCodec.VERY_SMALL; + + for (i = 0; i < lpcSize; i++) + mem_sw[i] = 0; + first = 1; + bounded_pitch = 1; + + /* Final signal synthesis from excitation */ + NSpeex.Filters.Iir_mem2(excBuf, excIdx, interp_qlpc, frmBuf, frmIdx, + frameSize, lpcSize, mem_sp); + + ins0[0] = frmBuf[frmIdx] + preemph * pre_mem2; + for (i = 1; i < frameSize; i++) + ins0[i] = frmBuf[frmIdx = i] + preemph * ins0[i - 1]; + pre_mem2 = ins0[frameSize - 1]; + + return 0; + } + + /* LSP Quantization */ + if (first != 0) + { + for (i = 0; i < lpcSize; i++) + old_lsp[i] = lsp[i]; + } + + /* Quantize LSPs */ + // #if 1 /*0 for unquantized*/ + submodes[submodeID].LsqQuant.Quant(lsp, qlsp, lpcSize, bits); + // #else + // for (i=0;i 15) + quant = 15; + if (quant < 0) + quant = 0; + bits.Pack(quant, 4); + ol_pitch_coef = (float)0.066667d * quant; + } + + /* Quantize and transmit open-loop excitation gain */ + { + int qe = (int)(Math.Floor(0.5d + 3.5d * Math.Log(ol_gain))); + if (qe < 0) + qe = 0; + if (qe > 31) + qe = 31; + ol_gain = (float)Math.Exp(qe / 3.5d); + bits.Pack(qe, 5); + } + + /* Special case for first frame */ + if (first != 0) + { + for (i = 0; i < lpcSize; i++) + old_qlsp[i] = qlsp[i]; + } + + /* Filter response */ + res = new float[subframeSize]; + /* Target signal */ + target = new float[subframeSize]; + syn_resp = new float[subframeSize]; + mem = new float[lpcSize]; + orig = new float[frameSize]; + for (i = 0; i < frameSize; i++) + orig[i] = frmBuf[frmIdx + i]; + + /* Loop on sub-frames */ + for (int sub = 0; sub < nbSubframes; sub++) + { + float tmp; + int offset; + int sp, sw, exc, exc2; + int pitchval; + + /* Offset relative to start of frame */ + offset = subframeSize * sub; + /* Original signal */ + sp = frmIdx + offset; + /* Excitation */ + exc = excIdx + offset; + /* Weighted signal */ + sw = swIdx + offset; + + exc2 = exc2Idx + offset; + + /* LSP interpolation (quantized and unquantized) */ + tmp = (float)(1.0d + sub) / nbSubframes; + for (i = 0; i < lpcSize; i++) + interp_lsp[i] = (1 - tmp) * old_lsp[i] + tmp * lsp[i]; + for (i = 0; i < lpcSize; i++) + interp_qlsp[i] = (1 - tmp) * old_qlsp[i] + tmp * qlsp[i]; + + /* Make sure the filters are stable */ + NSpeex.Lsp.Enforce_margin(interp_lsp, lpcSize, .002f); + NSpeex.Lsp.Enforce_margin(interp_qlsp, lpcSize, .002f); + + /* Compute interpolated LPCs (quantized and unquantized) */ + for (i = 0; i < lpcSize; i++) + interp_lsp[i] = (float)System.Math.Cos(interp_lsp[i]); + m_lsp.Lsp2lpc(interp_lsp, interp_lpc, lpcSize); + + for (i = 0; i < lpcSize; i++) + interp_qlsp[i] = (float)System.Math.Cos(interp_qlsp[i]); + m_lsp.Lsp2lpc(interp_qlsp, interp_qlpc, lpcSize); + + /* Compute analysis filter gain at w=pi (for use in SB-CELP) */ + tmp = 1; + pi_gain[sub] = 0; + for (i = 0; i <= lpcSize; i++) + { + pi_gain[sub] += tmp * interp_qlpc[i]; + tmp = -tmp; + } + + /* + * Compute bandwidth-expanded (unquantized) LPCs for perceptual + * weighting + */ + NSpeex.Filters.Bw_lpc(gamma1, interp_lpc, bw_lpc1, lpcSize); + if (gamma2 >= 0) + NSpeex.Filters.Bw_lpc(gamma2, interp_lpc, bw_lpc2, lpcSize); + else + { + bw_lpc2[0] = 1; + bw_lpc2[1] = -preemph; + for (i = 2; i <= lpcSize; i++) + bw_lpc2[i] = 0; + } + + /* Compute impulse response of A(z/g1) / ( A(z)*A(z/g2) ) */ + for (i = 0; i < subframeSize; i++) + excBuf[exc + i] = 0; + excBuf[exc] = 1; + NSpeex.Filters.Syn_percep_zero(excBuf, exc, interp_qlpc, bw_lpc1, + bw_lpc2, syn_resp, subframeSize, lpcSize); + + /* Reset excitation */ + for (i = 0; i < subframeSize; i++) + excBuf[exc + i] = 0; + for (i = 0; i < subframeSize; i++) + exc2Buf[exc2 + i] = 0; + + /* Compute zero response of A(z/g1) / ( A(z/g2) * A(z) ) */ + for (i = 0; i < lpcSize; i++) + mem[i] = mem_sp[i]; + NSpeex.Filters.Iir_mem2(excBuf, exc, interp_qlpc, excBuf, exc, + subframeSize, lpcSize, mem); + + for (i = 0; i < lpcSize; i++) + mem[i] = mem_sw[i]; + NSpeex.Filters.Filter_mem2(excBuf, exc, bw_lpc1, bw_lpc2, res, 0, + subframeSize, lpcSize, mem, 0); + + /* Compute weighted signal */ + for (i = 0; i < lpcSize; i++) + mem[i] = mem_sw[i]; + NSpeex.Filters.Filter_mem2(frmBuf, sp, bw_lpc1, bw_lpc2, swBuf, sw, + subframeSize, lpcSize, mem, 0); + + /* Compute target signal */ + for (i = 0; i < subframeSize; i++) + target[i] = swBuf[sw + i] - res[i]; + + for (i = 0; i < subframeSize; i++) + excBuf[exc + i] = exc2Buf[exc2 + i] = 0; + + /* If we have a long-term predictor (otherwise, something's wrong) */ + // if (submodes[submodeID].ltp.quant) + // { + int pit_min, pit_max; + /* Long-term prediction */ + if (submodes[submodeID].LbrPitch != -1) + { + /* Low bit-rate pitch handling */ + int margin; + margin = submodes[submodeID].LbrPitch; + if (margin != 0) + { + if (ol_pitch < min_pitch + margin - 1) + ol_pitch = min_pitch + margin - 1; + if (ol_pitch > max_pitch - margin) + ol_pitch = max_pitch - margin; + pit_min = ol_pitch - margin + 1; + pit_max = ol_pitch + margin; + } + else + { + pit_min = pit_max = ol_pitch; + } + } + else + { + pit_min = min_pitch; + pit_max = max_pitch; + } + + /* Force pitch to use only the current frame if needed */ + if (bounded_pitch != 0 && pit_max > offset) + pit_max = offset; + + /* Perform pitch search */ + pitchval = submodes[submodeID].Ltp.Quant(target, swBuf, sw, + interp_qlpc, bw_lpc1, bw_lpc2, excBuf, exc, pit_min, + pit_max, ol_pitch_coef, lpcSize, subframeSize, bits, + exc2Buf, exc2, syn_resp, complexity); + + pitch[sub] = pitchval; + + // } else { + // speex_error ("No pitch prediction, what's wrong"); + // } + + /* Update target for adaptive codebook contribution */ + NSpeex.Filters.Syn_percep_zero(excBuf, exc, interp_qlpc, bw_lpc1, + bw_lpc2, res, subframeSize, lpcSize); + for (i = 0; i < subframeSize; i++) + target[i] -= res[i]; + + /* Quantization of innovation */ + { + int innovptr; + float ener = 0, ener_1; + + innovptr = sub * subframeSize; + for (i = 0; i < subframeSize; i++) + innov[innovptr + i] = 0; + + NSpeex.Filters.Residue_percep_zero(target, 0, interp_qlpc, + bw_lpc1, bw_lpc2, buf2, subframeSize, lpcSize); + for (i = 0; i < subframeSize; i++) + ener += buf2[i] * buf2[i]; + ener = (float)Math.Sqrt(.1f + ener / subframeSize); + /* + * for (i=0;i= 1) + { + for (i = 0; i < lpcSize; i++) + old_lsp[i] = lsp[i]; + for (i = 0; i < lpcSize; i++) + old_qlsp[i] = qlsp[i]; + } + + if (submodeID == 1) + { + if (dtx_count != 0) + { + bits.Pack(15, 4); + } + else + { + bits.Pack(0, 4); + } + } + + /* The next frame will not be the first (Duh!) */ + first = 0; + + { + float ener_3 = 0, err = 0; + float snr; + for (i = 0; i < frameSize; i++) + { + ener_3 += frmBuf[frmIdx + i] * frmBuf[frmIdx + i]; + err += (frmBuf[frmIdx + i] - orig[i]) + * (frmBuf[frmIdx + i] - orig[i]); + } + snr = (float)(10 * Math.Log((ener_3 + 1) / (err + 1))); + /* + * System.out.println("Frame result: SNR="+snr+" E="+ener+" + * Err="+err+"\r\n"); + */ + } + + /* Replace input by synthesized speech */ + ins0[0] = frmBuf[frmIdx] + preemph * pre_mem2; + for (i = 1; i < frameSize; i++) + ins0[i] = frmBuf[frmIdx + i] + preemph * ins0[i - 1]; + pre_mem2 = ins0[frameSize - 1]; + + if (submodes[submodeID].Innovation is NoiseSearch || submodeID == 0) + bounded_pitch = 1; + else + bounded_pitch = 0; + + return 1; + } + + public virtual int EncodedFrameSize + { + get + { + return NSpeex.NbCodec.NB_FRAME_SIZE[submodeID]; + } + } + + public virtual int Quality + { + set + { + if (value < 0) + value = 0; + if (value > 10) + value = 10; + submodeID = submodeSelect = NB_QUALITY_MAP[value]; + } + } + + public virtual int BitRate + { + get + { + if (submodes[submodeID] != null) + return sampling_rate * submodes[submodeID].BitsPerFrame + / frameSize; + else + return sampling_rate * (NSpeex.NbCodec.NB_SUBMODE_BITS + 1) + / frameSize; + } + set + { + for (int i = 10; i >= 0; i--) + { + Quality = i; + if (BitRate <= value) + return; + } + } + } + + + public virtual int Mode + { + get + { + return submodeID; + } + set + { + if (value < 0) + value = 0; + submodeID = submodeSelect = value; + } + } + + + public virtual bool Vbr + { + get + { + return vbr_enabled != 0; + } + set + { + vbr_enabled = (value) ? 1 : 0; + } + } + + public virtual bool Vad + { + get + { + return vad_enabled != 0; + } + set + { + vad_enabled = (value) ? 1 : 0; + } + } + + public virtual bool Dtx + { + get + { + return dtx_enabled == 1; + } + set + { + dtx_enabled = (value) ? 1 : 0; + } + } + + public virtual int Abr + { + get + { + return abr_enabled; + } + set + { + abr_enabled = (value != 0) ? 1 : 0; + vbr_enabled = 1; + { + int i = 10, rate, target; + float vbr_qual; + target = value; + while (i >= 0) + { + Quality = i; + rate = BitRate; + if (rate <= target) + break; + i--; + } + vbr_qual = i; + if (vbr_qual < 0) + vbr_qual = 0; + VbrQuality = vbr_qual; + abr_count = 0; + abr_drift = 0; + abr_drift2 = 0; + } + } + } + + public virtual float VbrQuality + { + get + { + return vbr_quality; + } + set + { + if (value < 0f) + value = 0f; + if (value > 10f) + value = 10f; + vbr_quality = value; + } + } + + public virtual int Complexity + { + get + { + return complexity; + } + set + { + if (value < 0) + value = 0; + if (value > 10) + value = 10; + this.complexity = value; + } + } + + public virtual int SamplingRate + { + get + { + return sampling_rate; + } + set + { + sampling_rate = value; + } + } + + public virtual int LookAhead + { + get + { + return windowSize - frameSize; + } + } + + public virtual float RelativeQuality + { + get + { + return relative_quality; + } + } + } +} diff --git a/Assets/Scripts/OpenTS2/NSpeex/NbEncoder.cs.meta b/Assets/Scripts/OpenTS2/NSpeex/NbEncoder.cs.meta new file mode 100644 index 00000000..a0001875 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/NbEncoder.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f51f28cc52995bc439ce2859b7120313 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/NSpeex/NbLspQuant.cs b/Assets/Scripts/OpenTS2/NSpeex/NbLspQuant.cs new file mode 100644 index 00000000..a30398e8 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/NbLspQuant.cs @@ -0,0 +1,118 @@ +// +// Copyright (C) 2003 Jean-Marc Valin +// Copyright (C) 1999-2003 Wimba S.A., All Rights Reserved. +// Copyright (C) 2008 Filip Navara +// Copyright (C) 2009-2010 Christoph Frschl +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// - Neither the name of the Xiph.org Foundation nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +using System; + +namespace NSpeex +{ + /// + /// LSP Quantisation and Unquantisation (narrowband) + /// + internal class NbLspQuant : LspQuant + { + /// + /// Line Spectral Pair Quantification (narrowband). + /// + public sealed override void Quant(float[] lsp, float[] qlsp, int order, Bits bits) + { + int i; + float tmp1, tmp2; + int id; + float[] quant_weight = new float[NSpeex.LspQuant.MAX_LSP_SIZE]; + + for (i = 0; i < order; i++) + qlsp[i] = lsp[i]; + quant_weight[0] = 1 / (qlsp[1] - qlsp[0]); + quant_weight[order - 1] = 1 / (qlsp[order - 1] - qlsp[order - 2]); + for (i = 1; i < order - 1; i++) + { + tmp1 = 1 / ((.15f + qlsp[i] - qlsp[i - 1]) * (.15f + qlsp[i] - qlsp[i - 1])); + tmp2 = 1 / ((.15f + qlsp[i + 1] - qlsp[i]) * (.15f + qlsp[i + 1] - qlsp[i])); + quant_weight[i] = (tmp1 > tmp2) ? tmp1 : tmp2; + } + for (i = 0; i < order; i++) + qlsp[i] -= ((Single?)(.25d * i + .25d)).Value; + for (i = 0; i < order; i++) + qlsp[i] *= 256; + id = NSpeex.LspQuant.Lsp_quant(qlsp, 0, + NSpeex.Codebook_Constants.cdbk_nb, + NSpeex.Codebook_Constants.NB_CDBK_SIZE, order); + bits.Pack(id, 6); + + for (i = 0; i < order; i++) + qlsp[i] *= 2; + id = NSpeex.LspQuant.Lsp_weight_quant(qlsp, 0, quant_weight, 0, + NSpeex.Codebook_Constants.cdbk_nb_low1, + NSpeex.Codebook_Constants.NB_CDBK_SIZE_LOW1, 5); + bits.Pack(id, 6); + + for (i = 0; i < 5; i++) + qlsp[i] *= 2; + id = NSpeex.LspQuant.Lsp_weight_quant(qlsp, 0, quant_weight, 0, + NSpeex.Codebook_Constants.cdbk_nb_low2, + NSpeex.Codebook_Constants.NB_CDBK_SIZE_LOW2, 5); + bits.Pack(id, 6); + id = NSpeex.LspQuant.Lsp_weight_quant(qlsp, 5, quant_weight, 5, + NSpeex.Codebook_Constants.cdbk_nb_high1, + NSpeex.Codebook_Constants.NB_CDBK_SIZE_HIGH1, 5); + bits.Pack(id, 6); + + for (i = 5; i < 10; i++) + qlsp[i] *= 2; + id = NSpeex.LspQuant.Lsp_weight_quant(qlsp, 5, quant_weight, 5, + NSpeex.Codebook_Constants.cdbk_nb_high2, + NSpeex.Codebook_Constants.NB_CDBK_SIZE_HIGH2, 5); + bits.Pack(id, 6); + + for (i = 0; i < order; i++) + qlsp[i] *= ((Single?).00097656d).Value; + for (i = 0; i < order; i++) + qlsp[i] = lsp[i] - qlsp[i]; + } + + /// + /// Line Spectral Pair Unquantification (narrowband). + /// + public sealed override void Unquant(float[] lsp, int order, Bits bits) + { + for (int i = 0; i < order; i++) + lsp[i] = .25f * i + .25f; + UnpackPlus(lsp, NSpeex.Codebook_Constants.cdbk_nb, bits, 0.0039062f, 10, 0); + UnpackPlus(lsp, NSpeex.Codebook_Constants.cdbk_nb_low1, bits, 0.0019531f, 5, 0); + UnpackPlus(lsp, NSpeex.Codebook_Constants.cdbk_nb_low2, bits, 0.00097656f, 5, 0); + UnpackPlus(lsp, NSpeex.Codebook_Constants.cdbk_nb_high1, bits, 0.0019531f, 5, 5); + UnpackPlus(lsp, NSpeex.Codebook_Constants.cdbk_nb_high2, bits, 0.00097656f, 5, 5); + } + } +} diff --git a/Assets/Scripts/OpenTS2/NSpeex/NbLspQuant.cs.meta b/Assets/Scripts/OpenTS2/NSpeex/NbLspQuant.cs.meta new file mode 100644 index 00000000..f7179dcf --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/NbLspQuant.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 70125eae080a2a543b09807cce56556f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/NSpeex/NoiseSearch.cs b/Assets/Scripts/OpenTS2/NSpeex/NoiseSearch.cs new file mode 100644 index 00000000..3de221f4 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/NoiseSearch.cs @@ -0,0 +1,98 @@ +// +// Copyright (C) 2003 Jean-Marc Valin +// Copyright (C) 1999-2003 Wimba S.A., All Rights Reserved. +// Copyright (C) 2008 Filip Navara +// Copyright (C) 2009-2010 Christoph Frschl +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// - Neither the name of the Xiph.org Foundation nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +using System; +#if FIXED_POINT +using SpeexWord16 = System.Int16; +using SpeexWord32 = System.Int32; +#else +using SpeexWord16 = System.Single; +using SpeexWord32 = System.Single; +#endif + +namespace NSpeex +{ + /// + /// Noise codebook search + /// + internal class NoiseSearch : CodebookSearch + { + /// + /// Codebook Search Quantification (Noise). + /// + /// target vector + /// LPCs for this subframe + /// Weighted LPCs for this subframe + /// Weighted LPCs for this subframe + /// number of LPC coeffs + /// number of samples in subframe + /// excitation array. + /// position in excitation array. + /// + /// Speex bits buffer. + /// + public sealed override void Quantify( + SpeexWord16[] target, SpeexWord16[] ak, SpeexWord16[] awk1, + SpeexWord16[] awk2, int p, int nsf, SpeexWord32[] exc, int es, SpeexWord16[] r, + Bits bits, int complexity) + { + int i; + SpeexWord16[] tmp = new SpeexWord16[nsf]; + NSpeex.Filters.Residue_percep_zero(target, 0, ak, awk1, awk2, tmp, nsf, p); + + for (i = 0; i < nsf; i++) + exc[es + i] += tmp[i]; + for (i = 0; i < nsf; i++) + target[i] = 0; + } + + /// + /// Codebook Search Unquantification (Noise). + /// + /// + /// - + /// - + /// - + /// - + public sealed override void Unquantify(SpeexWord32[] exc, int es, int nsf, Bits bits) + { + for (int i = 0; i < nsf; i++) +#if FIXED_POINT + exc[es + i] += (int)((new Random().Next(Int16.MaxValue)) << 14); +#else + exc[es + i] += (float)(3.0d * (new Random().NextDouble() - .5d)); +#endif + } + } +} diff --git a/Assets/Scripts/OpenTS2/NSpeex/NoiseSearch.cs.meta b/Assets/Scripts/OpenTS2/NSpeex/NoiseSearch.cs.meta new file mode 100644 index 00000000..f0a04641 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/NoiseSearch.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bfdfd67963857c64ba15d032b055321f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/NSpeex/OggCrc.cs b/Assets/Scripts/OpenTS2/NSpeex/OggCrc.cs new file mode 100644 index 00000000..cee76357 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/OggCrc.cs @@ -0,0 +1,117 @@ +// +// Copyright (C) 2003 Jean-Marc Valin +// Copyright (C) 1999-2003 Wimba S.A., All Rights Reserved. +// Copyright (C) 2008 Filip Navara +// Copyright (C) 2009-2010 Christoph Frschl +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// - Neither the name of the Xiph.org Foundation nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +using System.Security.Cryptography; +using System; + +namespace NSpeex +{ + /// + /// Calculates the CRC checksum for Ogg packets. + /// + /// Ogg uses the same generator polynomial as ethernet, although with an + /// unreflected alg and an init/final of 0, not 0xffffffff. + /// + public class OggCrc : HashAlgorithm + { + private const uint Polynomial = 0x04c11db7; + private const uint Seed = 0; + + /// + /// CRC checksum lookup table. + /// + private static uint[] lookupTable; + + /// + /// Current value of the CRC checksum. + /// + private uint hash; + + static OggCrc() + { + lookupTable = new uint[256]; + for (uint i = 0; i < lookupTable.Length; i++) + { + uint entry = i << 24;//i; + for (int j = 0; j < 8; j++) + { + //if ((entry & 1) == 1) + if ((entry & 0x80000000) != 0) + entry = (entry << 1) ^ Polynomial; + else + entry <<= 1; + } + lookupTable[i] = entry; + } + } + + public override void Initialize() + { + this.hash = Seed; + } + + /// + /// Calculates the checksum on the given data, from the give offset and for + /// the given length, using the given initial value. This allows on to + /// calculate the checksum iteratively, by reinjecting the last returned + /// value as the initial value when the function is called for the next data + /// chunk. The initial value should be 0 for the first iteration. + /// + protected override void HashCore(byte[] array, int ibStart, int cbSize) + { + for (int i = 0; i < cbSize; i++) + { + unchecked + { + this.hash = (this.hash << 8) ^ lookupTable[(array[i + ibStart] ^ (this.hash >> 24)) & 0xff]; + } + } + } + + protected override byte[] HashFinal() + { + return new byte[] { + (byte)(this.hash & 0xff), + (byte)((this.hash >> 8) & 0xff), + (byte)((this.hash >> 16) & 0xff), + (byte)((this.hash >> 24) & 0xff) + }; + } + + public override int HashSize + { + get { return 32; } + } + } +} diff --git a/Assets/Scripts/OpenTS2/NSpeex/OggCrc.cs.meta b/Assets/Scripts/OpenTS2/NSpeex/OggCrc.cs.meta new file mode 100644 index 00000000..ce5aed13 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/OggCrc.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3327790f00d3eeb4088eedff1c173881 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/NSpeex/OggCrc2.cs b/Assets/Scripts/OpenTS2/NSpeex/OggCrc2.cs new file mode 100644 index 00000000..b01779af --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/OggCrc2.cs @@ -0,0 +1,47 @@ +namespace NSpeex +{ + /// + /// Calculates the CRC checksum for Ogg packets. + /// Ogg uses the same generator polynomial as ethernet, although with an unreflected alg and an init/final of 0, not 0xffffffff. + /// + public class OggCrc2 + { + private static int[] crc_lookup; + + static OggCrc2() + { + crc_lookup = new int[256]; + for (int i = 0; i < crc_lookup.Length; i++) + { + int r = i << 24; + for (int j = 0; j < 8; j++) + { + if ((r & 0x80000000) != 0) + { + /* The same as the ethernet generator polynomial, although we use an + unreflected alg and an init/final of 0, not 0xffffffff */ + r = (r << 1) ^ 0x04c11db7; + } + else + { + r <<= 1; + } + } + crc_lookup[i] = (int)(r & 0xffffffff); + } + } + + public static int checksum(int crc, + byte[] data, + int offset, + int length) + { + int end = offset + length; + for (; offset < end; offset++) + { + crc = (crc << 8) ^ crc_lookup[((crc >> 24) & 0xff) ^ (data[offset] & 0xff)]; + } + return crc; + } + } +} diff --git a/Assets/Scripts/OpenTS2/NSpeex/OggCrc2.cs.meta b/Assets/Scripts/OpenTS2/NSpeex/OggCrc2.cs.meta new file mode 100644 index 00000000..bd4d0871 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/OggCrc2.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e94af9186017b1442a81d69b0b26ac61 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/NSpeex/OggPageHeader.cs b/Assets/Scripts/OpenTS2/NSpeex/OggPageHeader.cs new file mode 100644 index 00000000..8c49defb --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/OggPageHeader.cs @@ -0,0 +1,64 @@ +using System; + +namespace NSpeex +{ + /// + /// Ogg Page Header + ///
    + ///
  • 0 - 3: capture_pattern
  • + ///
  • 4: stream_structure_version
  • + ///
  • 5: header_type_flag (0=normal, 2=bos: beginning of stream, 4=eos: end of stream).
  • + ///
  • 6 - 13: absolute granule position
  • + ///
  • 14 - 17: stream serial number
  • + ///
  • 18 - 21: page sequence no
  • + ///
  • 22 - 25: page checksum
  • + ///
  • 26: page_segments
  • + ///
  • 27 - x: segment_table
  • + ///
+ ///
+ public class OggPageHeader + { + public const int HEADER_TYPE_NORMAL = 0; + public const int HEADER_TYPE_BOS = 2; + public const int HEADER_TYPE_EOS = 4; + + public int HeaderType { get; set; } + public long GranulePos { get; set; } + public int StreamSerialNumber { get; set; } + + public int PageCount { get; set; } + + public int CheckSum { get; set; } + + public int PacketCount { get; set; } + + public byte[] PacketSizes { get; set; } + + public OggPageHeader(int headerType, long granulePos, int streamSerialNumber, int pageCount, int checkSum, int packetCount, byte[] packetSizes) + { + HeaderType = headerType; + GranulePos = granulePos; + StreamSerialNumber = streamSerialNumber; + PageCount = pageCount; + CheckSum = checkSum; + PacketCount = packetCount; + PacketSizes = packetSizes; + } + + public byte[] BuildData() + { + byte[] data = new byte[27+PacketCount]; + LittleEndian.WriteString(data,0,"OggS");//0 - 3: capture_pattern + data[4] = 0;//4: stream_structure_version + data[5] = (byte)(HeaderType);//5: header_type_flag + LittleEndian.WriteLong(data, 6, GranulePos);//6 - 13: absolute granule position + LittleEndian.WriteInt(data, 14, StreamSerialNumber);//14 - 17: stream serial number + LittleEndian.WriteInt(data, 18, PageCount);//18 - 21: page sequence no + LittleEndian.WriteInt(data, 22, CheckSum);//22 - 25: page checksum + data[26] = (byte)PacketCount; // 26: page_segments + Array.Copy(PacketSizes,0,data,27,PacketCount); + return data; + } + + } +} diff --git a/Assets/Scripts/OpenTS2/NSpeex/OggPageHeader.cs.meta b/Assets/Scripts/OpenTS2/NSpeex/OggPageHeader.cs.meta new file mode 100644 index 00000000..0d76d1e4 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/OggPageHeader.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1ad3c5a7947c38c449877a81c528b4ce +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/NSpeex/OggSpeexWriter.cs b/Assets/Scripts/OpenTS2/NSpeex/OggSpeexWriter.cs new file mode 100644 index 00000000..8a2cf709 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/OggSpeexWriter.cs @@ -0,0 +1,316 @@ +// +// Copyright (C) 2003 Jean-Marc Valin +// Copyright (C) 1999-2003 Wimba S.A., All Rights Reserved. +// Copyright (C) 2008 Filip Navara +// Copyright (C) 2009-2010 Christoph Frschl +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// - Neither the name of the Xiph.org Foundation nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +using System.IO; +using System; + +namespace NSpeex +{ + /// + /// Ogg Speex Writer + /// + public class OggSpeexWriter : AudioFileWriter + { + /// + /// Number of packets in an Ogg page (must be less than 255) + /// + public const int PACKETS_PER_OGG_PAGE = 250; + + /// + /// The OutputStream + /// + private BinaryWriter xout; + + /// + /// Defines the encoder mode (0=NB, 1=WB and 2-UWB). + /// + private readonly int mode; + + /// + /// Defines the sampling rate of the audio input. + /// + private readonly int sampleRate; + + /// + /// Defines the number of channels of the audio input (1=mono, 2=stereo). + /// + private readonly int channels; + + /// + /// Defines the number of frames per speex packet. + /// + private readonly int nframes; + + /// + /// Defines whether or not to use VBR (Variable Bit Rate). + /// + private readonly bool vbr; + + /// + /// Ogg Stream Serial Number + /// + private int streamSerialNumber; + + /// + /// Data buffer + /// + private byte[] dataBuffer; + + /// + /// Pointer within the Data buffer + /// + private int dataBufferPtr; + + /// + /// Header buffer + /// + private byte[] headerBuffer; + + /// + /// Pointer within the Header buffer + /// + private int headerBufferPtr; + + /// + /// Ogg Page count + /// + private int pageCount; + + /// + /// Speex packet count within an Ogg Page + /// + private int packetCount; + + /// + /// Absolute granule position (the number of audio samples from beginning of + /// file to end of Ogg Packet). + /// + private long granulepos; + + /// + /// Builds an Ogg Speex Writer. + /// + /// the mode of the encoder (0=NB, 1=WB, 2=UWB). + /// the number of samples per second. + /// the number of audio channels (1=mono, 2=stereo, ...). + /// the number of frames per speex packet. + public OggSpeexWriter( + int mode, int sampleRate, + int channels, int nframes, bool vbr) + { + streamSerialNumber = new Random().Next(); + dataBuffer = new byte[65565]; + dataBufferPtr = 0; + headerBuffer = new byte[255]; + headerBufferPtr = 0; + pageCount = 0; + packetCount = 0; + granulepos = 0; + + this.mode = mode; + this.sampleRate = sampleRate; + this.channels = channels; + this.nframes = nframes; + this.vbr = vbr; + } + + public int SerialNumber + { + set + { + this.streamSerialNumber = value; + } + } + + /// + /// Closes the output file. + /// + /// + public override void Close() + { + Flush(true); + xout.Close(); + } + + /// + /// Open the output file. + /// + /// + public override void Open(Stream stream) + { + xout = new BinaryWriter(stream); + } + + /// + /// Writes an Ogg Page Header to the given byte array. + /// + /// + /// the buffer to write to. + /// the from which to start writing. + /// the header type flag (0=normal, 2=bos: beginning of stream, + /// the absolute granule position. + /// + /// + /// + /// + /// the amount of data written to the buffer. + private static int WriteOggPageHeader(BinaryWriter buf, + int headerType, long granulepos, int streamSerialNumber, + int pageCount, int packetCount, byte[] packetSizes) + { + buf.Write(System.Text.Encoding.UTF8.GetBytes("OggS")); // 0 - 3: capture_pattern + buf.Write(Byte.MinValue); // 4: stream_structure_version + buf.Write((byte)headerType); // 5: header_type_flag + buf.Write(granulepos); // 6 - 13: absolute granule + // position + buf.Write(streamSerialNumber); // 14 - 17: stream + // serial number + buf.Write(pageCount); // 18 - 21: page sequence no + buf.Write(0); // 22 - 25: page checksum + buf.Write((byte)packetCount); // 26: page_segments + buf.Write(packetSizes, 0, packetCount); + return packetCount + 27; + } + + /// + /// Builds and returns an Ogg Page Header. + /// + /// + /// the header type flag (0=normal, 2=bos: beginning of stream, + /// the absolute granule position. + /// + /// + /// + /// + /// an Ogg Page Header. + private static byte[] BuildOggPageHeader(int headerType, long granulepos, + int streamSerialNumber, int pageCount, int packetCount, + byte[] packetSizes) + { + byte[] data = new byte[packetCount + 27]; + WriteOggPageHeader(new BinaryWriter(new MemoryStream(data)), headerType, granulepos, streamSerialNumber, + pageCount, packetCount, packetSizes); + return data; + } + + /// + /// Writes the header pages that start the Ogg Speex file. Prepares file for + /// data to be written. + /// + /// + /// description to be included in the header. + /// @exception IOException + public override void WriteHeader(String comment) + { + byte[] header; + byte[] data; + NSpeex.OggCrc crc = new NSpeex.OggCrc(); + /* writes the OGG header page */ + header = BuildOggPageHeader(2, 0, + streamSerialNumber, pageCount++, 1, new byte[] { 80 }); + data = NSpeex.AudioFileWriter.BuildSpeexHeader(sampleRate, mode, + channels, vbr, nframes); + crc.Initialize(); + crc.TransformBlock(header, 0, header.Length, header, 0); + crc.TransformFinalBlock(data, 0, data.Length); + xout.Write(header, 0, 22); + xout.Write(crc.Hash, 0, crc.HashSize / 8); + xout.Write(header, 26, header.Length - 26); + xout.Write(data, 0, data.Length); + /* writes the OGG comment page */ + header = BuildOggPageHeader(0, 0, + streamSerialNumber, pageCount++, 1, + new byte[] { (byte)(comment.Length + 8) }); + data = NSpeex.AudioFileWriter.BuildSpeexComment(comment); + crc.Initialize(); + crc.TransformBlock(header, 0, header.Length, header, 0); + crc.TransformFinalBlock(data, 0, data.Length); + xout.Write(header, 0, 22); + xout.Write(crc.Hash, 0, crc.HashSize / 8); + xout.Write(header, 26, header.Length - 26); + xout.Write(data, 0, data.Length); + } + + /// + /// Writes a packet of audio. + /// + /// + /// - + /// - + /// - + /// @exception IOException + public override void WritePacket(byte[] data, int offset, int len) + { + if (len <= 0) + { // nothing to write + return; + } + if (packetCount > PACKETS_PER_OGG_PAGE) + { + Flush(false); + } + System.Array.Copy(data, offset, dataBuffer, dataBufferPtr, len); + dataBufferPtr += len; + headerBuffer[headerBufferPtr++] = (byte)len; + packetCount++; + granulepos += nframes * ((mode == 2) ? 640 : ((mode == 1) ? 320 : 160)); + } + + /// + /// Flush the Ogg page out of the buffers into the file. + /// + /// + /// - + /// @exception IOException + private void Flush(bool eos) + { + byte[] header; + NSpeex.OggCrc crc = new NSpeex.OggCrc(); + /* writes the OGG header page */ + header = BuildOggPageHeader(((eos) ? 4 : 0), + granulepos, streamSerialNumber, pageCount++, packetCount, + headerBuffer); + crc.Initialize(); + crc.TransformBlock(header, 0, header.Length, header, 0); + crc.TransformFinalBlock(dataBuffer, 0, dataBufferPtr); + xout.Write(header, 0, 22); + xout.Write(crc.Hash, 0, crc.HashSize / 8); + xout.Write(header, 26, header.Length - 26); + xout.Write(dataBuffer, 0, dataBufferPtr); + dataBufferPtr = 0; + headerBufferPtr = 0; + packetCount = 0; + } + } +} diff --git a/Assets/Scripts/OpenTS2/NSpeex/OggSpeexWriter.cs.meta b/Assets/Scripts/OpenTS2/NSpeex/OggSpeexWriter.cs.meta new file mode 100644 index 00000000..d453c6c1 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/OggSpeexWriter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a449a267dbe04354396e49513ef74ed5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/NSpeex/OggSpeexWriter2.cs b/Assets/Scripts/OpenTS2/NSpeex/OggSpeexWriter2.cs new file mode 100644 index 00000000..6f723a0b --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/OggSpeexWriter2.cs @@ -0,0 +1,171 @@ +using System; +using System.IO; +using System.Text; + +namespace NSpeex +{ + public class OggSpeexWriter2 : AbsAudioWriter + { + public const int PACKETS_PER_OGG_PAGE = 250; + + private Stream stream; + + /** Defines the encoder mode (0=NB, 1=WB and 2-UWB). */ + private BandMode mode; + /** Defines the sampling rate of the audio input. */ + private int sampleRate; + /** Defines the number of channels of the audio input (1=mono, 2=stereo). */ + private int channels; + /** Defines the number of frames per speex packet. */ + private int nframes; + /** Defines whether or not to use VBR (Variable Bit Rate). */ + private bool vbr; + + private int bitRate; + + private int size; + /** Ogg Stream Serial Number */ + private int streamSerialNumber; + /** Data buffer */ + private byte[] dataBuffer; + /** Pointer within the Data buffer */ + private int dataBufferPtr; + /** Header buffer */ + private byte[] headerBuffer; + /** Pointer within the Header buffer */ + private int headerBufferPtr; + /** Ogg Page count */ + private int pageCount; + /** Speex packet count within an Ogg Page */ + private int packetCount; + /** + * Absolute granule position + * (the number of audio samples from beginning of file to end of Ogg Packet). + */ + private long granulepos; + + private long packetDataSize = 0; + + private OggSpeexWriter2() + { + if (streamSerialNumber == 0) + { + streamSerialNumber = new Random().Next(); + } + dataBuffer = new byte[65565]; + dataBufferPtr = 0; + headerBuffer = new byte[255]; + headerBufferPtr = 0; + pageCount = 0; + packetCount = 0; + granulepos = 0; + } + + public OggSpeexWriter2(BandMode mode, int sampleRate, int channels, int nframes, bool vbr, int bitRate) + : this() + { + this.mode = mode; + this.sampleRate = sampleRate; + this.channels = channels; + this.nframes = nframes; + this.vbr = vbr; + this.bitRate = bitRate; + } + + public override void Close() + { + + Flush(true); + stream.Close(); + } + + public override void WriteHeader(string comment) + { + OggPageHeader pageHeader = new OggPageHeader(OggPageHeader.HEADER_TYPE_BOS, 0, streamSerialNumber, pageCount++, 0, 1, new byte[1] { 80 }); + byte[] pageHeaderData = pageHeader.BuildData(); + + + SpeexHeader speexHeader = new SpeexHeader(sampleRate, mode, channels, vbr, bitRate, nframes); + byte[] speexHeaderData = speexHeader.BuildData(); + + int chksum = OggCrc2.checksum(0, pageHeaderData, 0, pageHeaderData.Length); + chksum = OggCrc2.checksum(chksum, speexHeaderData, 0, speexHeaderData.Length); + LittleEndian.WriteInt(pageHeaderData, 22, chksum); + + //Misc.ShowBytes(pageHeaderData, 0, pageHeaderData.Length); + //Misc.ShowBytes(speexHeaderData, 0, speexHeaderData.Length); + + stream.Write(pageHeaderData, 0, pageHeaderData.Length); + stream.Write(speexHeaderData, 0, speexHeaderData.Length); + + //Console.WriteLine("write page header:" + pageHeaderData.Length); + //Console.WriteLine("write speex header:" + speexHeaderData.Length); + //comment + pageHeader = new OggPageHeader(OggPageHeader.HEADER_TYPE_NORMAL, 0, streamSerialNumber, pageCount++, 0, 1, new byte[1] { (byte)(comment.Length + 8) }); + pageHeaderData = pageHeader.BuildData(); + speexHeaderData = new byte[comment.Length + 8]; + LittleEndian.WriteInt(speexHeaderData, 0, comment.Length); + LittleEndian.WriteString(speexHeaderData, 4, comment); + LittleEndian.WriteInt(speexHeaderData, 4 + comment.Length, 0); + chksum = OggCrc2.checksum(0, pageHeaderData, 0, pageHeaderData.Length); + chksum = OggCrc2.checksum(chksum, speexHeaderData, 0, speexHeaderData.Length); + LittleEndian.WriteInt(pageHeaderData, 22, chksum); + stream.Write(pageHeaderData, 0, pageHeaderData.Length); + stream.Write(speexHeaderData, 0, speexHeaderData.Length); + + //Misc.ShowBytes(pageHeaderData, 0, pageHeaderData.Length); + //Misc.ShowBytes(speexHeaderData, 0, speexHeaderData.Length); + //Console.WriteLine("write page header:" + pageHeaderData.Length); + //Console.WriteLine("write speex comment:" + speexHeaderData.Length); + } + + public override void WritePackage(byte[] data, int offset, int len) + { + if (len <= 0) + { // nothing to write + return; + } + if (packetCount > PACKETS_PER_OGG_PAGE) + { + Flush(false); + } + Array.Copy(data, offset, dataBuffer, dataBufferPtr, len); + dataBufferPtr += len; + headerBuffer[headerBufferPtr++] = (byte)len; + packetCount++; + granulepos += nframes * (mode == BandMode.UltraWide ? 640 : (mode == BandMode.Wide ? 320 : 160)); + } + + public void WritePackage(SpeexPacket packet) + { + WritePackage(packet.Data, 0, packet.Size); + } + + public override void Open(string path) + { + stream = File.Create(path); + size = 0; + } + + private void Flush(bool eos) + { + OggPageHeader pageHeader = new OggPageHeader((eos ? OggPageHeader.HEADER_TYPE_EOS : OggPageHeader.HEADER_TYPE_NORMAL), granulepos, streamSerialNumber, pageCount++, 0, packetCount, headerBuffer); + byte[] pageHeaderData = pageHeader.BuildData(); + int chksum = OggCrc2.checksum(0, pageHeaderData, 0, pageHeaderData.Length); + chksum = OggCrc2.checksum(chksum, dataBuffer, 0, dataBufferPtr); + LittleEndian.WriteInt(pageHeaderData, 22, chksum); + stream.Write(pageHeaderData, 0, pageHeaderData.Length); + stream.Write(dataBuffer, 0, dataBufferPtr); + packetDataSize += dataBufferPtr; + + dataBufferPtr = 0; + headerBufferPtr = 0; + packetCount = 0; + if (eos) + { + Console.WriteLine("total write " + packetDataSize +" packet data int byte"); + } + } + + } +} diff --git a/Assets/Scripts/OpenTS2/NSpeex/OggSpeexWriter2.cs.meta b/Assets/Scripts/OpenTS2/NSpeex/OggSpeexWriter2.cs.meta new file mode 100644 index 00000000..78e9cc88 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/OggSpeexWriter2.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 60008d39f04039848b22ee8c267d1c18 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/NSpeex/PcmWaveWriter.cs b/Assets/Scripts/OpenTS2/NSpeex/PcmWaveWriter.cs new file mode 100644 index 00000000..b5883cbc --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/PcmWaveWriter.cs @@ -0,0 +1,335 @@ +// +// Copyright (C) 2003 Jean-Marc Valin +// Copyright (C) 1999-2003 Wimba S.A., All Rights Reserved. +// Copyright (C) 2008 Filip Navara +// Copyright (C) 2009-2010 Christoph Frschl +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// - Neither the name of the Xiph.org Foundation nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +using System.IO; +using System; + +namespace NSpeex +{ + /// + /// Writes basic PCM wave files from binary audio data. + /// + /// Here's an example that writes 2 seconds of silence + /// + /// PcmWaveWriter s_wsw = new PcmWaveWriter(2, 44100); + /// byte[] silence = new byte[16/// 2/// 44100]; + /// wsw.Open("C:\\out.wav"); + /// wsw.WriteHeader(); + /// wsw.WriteData(silence, 0, silence.length); + /// wsw.WriteData(silence, 0, silence.length); + /// wsw.Close(); + /// + public class PcmWaveWriter : AudioFileWriter + { + /// + /// Wave type code of PCM + /// + protected const short WAVE_FORMAT_PCM = (short)0x01; + + /// + /// Wave type code of Speex + /// + protected const short WAVE_FORMAT_SPEEX = unchecked((short)0xa109); + + /// + /// Table describing the number of frames per packet in a Speex Wave file, + /// depending on its mode (0=NB, 1=WB, 3=UWB), channels-1 (1=mono, + /// 2=stereo) and the quality setting (0 to 10). See end of file for exerpt + /// from SpeexACM code for more explanations. + /// + public static readonly int[,,] WAVE_FRAME_SIZES = new int[,,] + { + { + { 8, 8, 8, 1, 1, 2, 2, 2, 2, 2, 2 }, // NB mono + { 2, 1, 1, 7, 7, 8, 8, 8, 8, 3, 3 } // NB stereo + }, + { + { 8, 8, 8, 2, 1, 1, 2, 2, 2, 2, 2 }, // WB mono + { 1, 2, 2, 8, 7, 6, 3, 3, 3, 3, 3 } // WB stereo + }, + { + { 8, 8, 8, 1, 2, 2, 1, 1, 1, 1, 1 }, // UWB mono + { 2, 1, 1, 7, 8, 3, 6, 6, 5, 5, 5 } // UWB stereo + } + }; + + /// + /// Table describing the number of bit per Speex frame, depending on its + /// mode (0=NB, 1=WB, 2=UWB), channels-1 (1=mono, 2=stereo) and the quality + /// setting (0 to 10). See end of file for exerpt from SpeexACM code for more + /// explanations. + /// + public static readonly int[,,] WAVE_BITS_PER_FRAME = new int[,,] + { + { + { 43, 79, 119, 160, 160, 220, 220, 300, 300, 364, 492 }, // NB mono + { 60, 96, 136, 177, 177, 237, 237, 317, 317, 381, 509 } // NB stereo + }, + { + { 79, 115, 155, 196, 256, 336, 412, 476, 556, 684, 844 }, // WB mono + { 96, 132, 172, 213, 273, 353, 429, 493, 573, 701, 861 } // WB stereo + }, + { + { 83, 151, 191, 232, 292, 372, 448, 512, 592, 720, 880 }, // UWB mono + { 100, 168, 208, 249, 309, 389, 465, 529, 609, 737, 897 } // UWB stereo + } + }; + + private BinaryWriter raf; + + /// + /// Defines the encoder mode (0=NB, 1=WB and 2-UWB). + /// + private readonly int mode; + private readonly int quality; + + /// + /// Defines the sampling rate of the audio input. + /// + private readonly int sampleRate; + + /// + /// Defines the number of channels of the audio input (1=mono, 2=stereo). + /// + private readonly int channels; + + /// + /// Defines the number of frames per speex packet. + /// + private readonly int nframes; + + /// + /// Defines whether or not to use VBR (Variable Bit Rate). + /// + private readonly bool vbr; + + private bool isPCM; + + private int size; + + /// + /// Constructor for PCM Wave file. + /// + /// the number of samples per second. + /// the number of audio channels (1=mono, 2=stereo, ...). + public PcmWaveWriter(int sampleRate, int channels) + { + this.sampleRate = sampleRate; + this.channels = channels; + isPCM = true; + } + + /// + /// Constructor for a Speex Wave file. + /// + /// the mode of the encoder (0=NB, 1=WB, 2=UWB). + /// + /// the number of samples per second. + /// the number of audio channels (1=mono, 2=stereo, ...). + /// the number of frames per speex packet. + /// + public PcmWaveWriter( + int mode, int quality, + int sampleRate, int channels, int nframes, + bool vbr) + { + this.mode = mode; + this.quality = quality; + this.sampleRate = sampleRate; + this.channels = channels; + this.nframes = nframes; + this.vbr = vbr; + isPCM = false; + } + + /// + /// Closes the output file. MUST be called to have a correct stream. + /// + /// + public override void Close() + { + // Update the total file length field from RIFF chunk + raf.BaseStream.Seek(4, System.IO.SeekOrigin.Begin); + int fileLength = (int)raf.BaseStream.Length - 8; + raf.Write(fileLength); + + // Update the data chunk length size + raf.BaseStream.Seek(40, System.IO.SeekOrigin.Begin); + raf.Write(size); + + // Close the output file + raf.Close(); + } + + /// + /// Open the output file. + /// + /// + public override void Open(Stream stream) + { + raf = new BinaryWriter(stream); + size = 0; + } + + /// + /// Writes the initial data chunks that start the wave file. Prepares file + /// for data samples to written. + /// + /// ignored by the WAV header. + /// + public override void WriteHeader(String comment) + { + // Writes the RIFF chunk indicating wave format + byte[] chkid = System.Text.Encoding.UTF8.GetBytes("RIFF"); + raf.Write(chkid, 0, chkid.Length); + raf.Write(0); /* total length must be blank */ + chkid = System.Text.Encoding.UTF8.GetBytes("WAVE"); + raf.Write(chkid, 0, chkid.Length); + + /* format subchunk: of size 16 */ + chkid = System.Text.Encoding.UTF8.GetBytes("fmt "); + raf.Write(chkid, 0, chkid.Length); + if (isPCM) + { + raf.Write(16); // Size of format chunk + raf.Write(WAVE_FORMAT_PCM); // Format tag: PCM + raf.Write((short)channels); // Number of channels + raf.Write(sampleRate); // Sampling frequency + raf.Write(sampleRate * channels * 2); // Average bytes per second + raf.Write((short)(channels * 2)); // Blocksize of data + raf.Write((short)16); // Bits per sample + } + else + { + int length = comment.Length; + raf.Write((short)(18 + 2 + 80 + length)); // Size of format chunk + raf.Write(WAVE_FORMAT_SPEEX); // Format tag: Speex + raf.Write((short)channels); // Number of channels + raf.Write(sampleRate); // Sampling frequency + raf.Write((CalculateEffectiveBitrate(mode, channels, quality) + 7) >> 3); // Average bytes per second + raf.Write((short)CalculateBlockSize(mode, channels, quality)); // Blocksize of data + raf.Write((short)quality); // Bits per sample + raf.Write((short)(2 + 80 + length)); // The count in bytes of the extra size + // FIXME: Probably wrong!!! + raf.Write(0xff & 1); // ACM major version number + raf.Write(0xff & 0); // ACM minor version number + raf.Write(NSpeex.AudioFileWriter.BuildSpeexHeader(sampleRate, mode, + channels, vbr, nframes)); + raf.Write(comment); + } + + /* write the start of data chunk */ + chkid = System.Text.Encoding.UTF8.GetBytes("data"); + raf.Write(chkid, 0, chkid.Length); + raf.Write(0); + } + + /// + /// Writes a packet of audio. + /// + /// audio data + /// the offset from which to start reading the data. + /// the length of data to read. + /// + public override void WritePacket(byte[] data, int offset, int len) + { + raf.Write(data, offset, len); + size += len; + } + + /// + /// Calculates effective bitrate (considering padding). See end of file for + /// exerpt from SpeexACM code for more explanations. + /// + /// effective bitrate (considering padding). + private static int CalculateEffectiveBitrate(int mode, int channels, int quality) + { + return ((((WAVE_FRAME_SIZES[mode, channels - 1, quality] * WAVE_BITS_PER_FRAME[mode, channels - 1, quality]) + 7) >> 3) * 50 * 8) + / WAVE_BITS_PER_FRAME[mode, channels - 1, quality]; + } + + /// + /// Calculates block size (considering padding). See end of file for exerpt + /// from SpeexACM code for more explanations. + /// + /// block size (considering padding). + private static int CalculateBlockSize(int mode, + int channels, int quality) + { + return (((WAVE_FRAME_SIZES[mode, channels - 1, quality] * WAVE_BITS_PER_FRAME[mode, channels - 1, quality]) + 7) >> 3); + } + } + + // The following is taken from the SpeexACM 1.0.1.1 Source code (codec.c file). + + // + // This array describes how many bits are required by an encoded audio frame. + // It also specifies the optimal framesperblock parameter to minimize + // padding loss. It also lists the effective bitrate (considering padding). + // + // The array indices are rate, channels, quality (each as a 0 based index) + // + /* + * struct tagQualityInfo { UINT nBitsPerFrame; UINT nFrameSize; UINT + * nFramesPerBlock; UINT nEffectiveBitrate; } QualityInfo[3][2][11] = { 43, 160, + * 8, 2150, // 8000 1 0 79, 160, 8, 3950, // 8000 1 1 119, 160, 8, 5950, // 8000 + * 1 2 160, 160, 1, 8000, // 8000 1 3 160, 160, 1, 8000, // 8000 1 4 220, 160, + * 2, 11000, // 8000 1 5 220, 160, 2, 11000, // 8000 1 6 300, 160, 2, 15000, // + * 8000 1 7 300, 160, 2, 15000, // 8000 1 8 364, 160, 2, 18200, // 8000 1 9 492, + * 160, 2, 24600, // 8000 1 10 60, 160, 2, 3000, // 8000 2 0 96, 160, 1, 4800, // + * 8000 2 1 136, 160, 1, 6800, // 8000 2 2 177, 160, 7, 8857, // 8000 2 3 177, + * 160, 7, 8857, // 8000 2 4 237, 160, 8, 11850, // 8000 2 5 237, 160, 8, 11850, // + * 8000 2 6 317, 160, 8, 15850, // 8000 2 7 317, 160, 8, 15850, // 8000 2 8 381, + * 160, 3, 19066, // 8000 2 9 509, 160, 3, 25466, // 8000 2 10 79, 320, 8, 3950, // + * 16000 1 0 115, 320, 8, 5750, // 16000 1 1 155, 320, 8, 7750, // 16000 1 2 + * 196, 320, 2, 9800, // 16000 1 3 256, 320, 1, 12800, // 16000 1 4 336, 320, 1, + * 16800, // 16000 1 5 412, 320, 2, 20600, // 16000 1 6 476, 320, 2, 23800, // + * 16000 1 7 556, 320, 2, 27800, // 16000 1 8 684, 320, 2, 34200, // 16000 1 9 + * 844, 320, 2, 42200, // 16000 1 10 96, 320, 1, 4800, // 16000 2 0 132, 320, 2, + * 6600, // 16000 2 1 172, 320, 2, 8600, // 16000 2 2 213, 320, 8, 10650, // + * 16000 2 3 273, 320, 7, 13657, // 16000 2 4 353, 320, 6, 17666, // 16000 2 5 + * 429, 320, 3, 21466, // 16000 2 6 493, 320, 3, 24666, // 16000 2 7 573, 320, + * 3, 28666, // 16000 2 8 701, 320, 3, 35066, // 16000 2 9 861, 320, 3, 43066, // + * 16000 2 10 83, 640, 8, 4150, // 32000 1 0 151, 640, 8, 7550, // 32000 1 1 + * 191, 640, 8, 9550, // 32000 1 2 232, 640, 1, 11600, // 32000 1 3 292, 640, 2, + * 14600, // 32000 1 4 372, 640, 2, 18600, // 32000 1 5 448, 640, 1, 22400, // + * 32000 1 6 512, 640, 1, 25600, // 32000 1 7 592, 640, 1, 29600, // 32000 1 8 + * 720, 640, 1, 36000, // 32000 1 9 880, 640, 1, 44000, // 32000 1 10 100, 640, + * 2, 5000, // 32000 2 0 168, 640, 1, 8400, // 32000 2 1 208, 640, 1, 10400, // + * 32000 2 2 249, 640, 7, 12457, // 32000 2 3 309, 640, 8, 15450, // 32000 2 4 + * 389, 640, 3, 19466, // 32000 2 5 465, 640, 6, 23266, // 32000 2 6 529, 640, + * 6, 26466, // 32000 2 7 609, 640, 5, 30480, // 32000 2 8 737, 640, 5, 36880, // + * 32000 2 9 897, 640, 5, 44880, // 32000 2 10 }; + */ +} diff --git a/Assets/Scripts/OpenTS2/NSpeex/PcmWaveWriter.cs.meta b/Assets/Scripts/OpenTS2/NSpeex/PcmWaveWriter.cs.meta new file mode 100644 index 00000000..551158c4 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/PcmWaveWriter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2ffc063127c1f2349a2d03feb07dff6e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/NSpeex/README.md b/Assets/Scripts/OpenTS2/NSpeex/README.md new file mode 100644 index 00000000..b415bcdf --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/README.md @@ -0,0 +1,31 @@ +# NSpeex +>早在11-12年,由于一个游戏项目要使用到语音压缩库,当时选用了speex,我们当时使用的是Unity3D游戏引擎,由于市面上没有.Net平台下的speex的库,于是我便将jspeex翻译成NSpeex。但是后来由于种种原因不再维护项目,前段时间有人问我这个库该怎么用,我就使用别人的[NSpeex](http://nspeex.codeplex.com/)库来进行解释说明,毕竟我之前的代码太像Java风格了,于是我将别人的代码复制过来,自己写点文档方便别人 +## 例子(example) +见 Test/SpeexTest.cs,将male.wav 转化为result.spx文件,然后使用foobar播放器可以播放 + +## 编码(encode) +``` +// byte[] dataIn -> byte[] dataOut +// convert to short +short[] data = new short[dataIn.Length / 2]; +Buffer.BlockCopy(dataIn, 0, data, 0, dataIn.Length); +byte[] dataOut = new byte[dataIn.Length]; +int encSize = speexEncoder.Encode(data, 0, data.Length, dataOut, 0, dataOut.Length); +if(encSize > 0){ + // encode success + // todo with dataOut[0-encSize] +} + +``` +## 解码(decode) +``` +// byte[] dataIn -> byte[] dataOut +short[] data = new short[1024]; +int decSize = speexEncoder.Decode(dataIn, 0, dataIn.Length, data, 0, false); + +if(decSize > 0 ){ + byte[] dataOut = new byte[1024]; + Buffer.BlockCopy(data, 0, dataOut, 0, decSize); + // todo with dataOut[0-decSize] +} +``` \ No newline at end of file diff --git a/Assets/Scripts/OpenTS2/NSpeex/README.md.meta b/Assets/Scripts/OpenTS2/NSpeex/README.md.meta new file mode 100644 index 00000000..e20b8922 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/README.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 869a233f4b66f83428a7a7c8e0681552 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/NSpeex/RawWriter.cs b/Assets/Scripts/OpenTS2/NSpeex/RawWriter.cs new file mode 100644 index 00000000..c98c5ccf --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/RawWriter.cs @@ -0,0 +1,87 @@ +// +// Copyright (C) 2003 Jean-Marc Valin +// Copyright (C) 1999-2003 Wimba S.A., All Rights Reserved. +// Copyright (C) 2008 Filip Navara +// Copyright (C) 2009-2010 Christoph Frschl +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// - Neither the name of the Xiph.org Foundation nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +using System.IO; +using System; + +namespace NSpeex +{ + /// + /// Raw Audio File Writer. + /// + public class RawWriter : AudioFileWriter + { + private Stream xout; + + /// + /// Closes the output file. + /// + public override void Close() + { + xout.Close(); + } + + /// + /// Open the output file. + /// + /// + public override void Open(Stream stream) + { + xout = stream; + } + + /// + /// Writes the header pages that start the Ogg Speex file. Prepares file for + /// data to be written. + /// + /// description to be included in the header. + /// + public override void WriteHeader(String comment) + { + // a raw audio file has no header + } + + /// + /// Writes a packet of audio. + /// + /// audio data + /// the offset from which to start reading the data. + /// the length of data to read. + /// + public override void WritePacket(byte[] data, int offset, int len) + { + xout.Write(data, offset, len); + } + } +} diff --git a/Assets/Scripts/OpenTS2/NSpeex/RawWriter.cs.meta b/Assets/Scripts/OpenTS2/NSpeex/RawWriter.cs.meta new file mode 100644 index 00000000..d077a6a2 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/RawWriter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e02b6f03d0e25a246ac9c58f31557514 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/NSpeex/SbCodec.cs b/Assets/Scripts/OpenTS2/NSpeex/SbCodec.cs new file mode 100644 index 00000000..36ec99ef --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/SbCodec.cs @@ -0,0 +1,190 @@ +// +// Copyright (C) 2003 Jean-Marc Valin +// Copyright (C) 1999-2003 Wimba S.A., All Rights Reserved. +// Copyright (C) 2008 Filip Navara +// Copyright (C) 2009-2010 Christoph Frschl +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// - Neither the name of the Xiph.org Foundation nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +namespace NSpeex +{ + /// + /// Sideband Codec. This class contains all the basic structures needed by the + /// Sideband encoder and decoder. + /// + internal class SbCodec : NbCodec + { + #region Constants + + /// + /// The Sideband Frame Size gives the size in bits of a Sideband frame for a + /// given sideband submode. + /// + public static readonly int[] SB_FRAME_SIZE = { 4, 36, 112, 192, 352, -1, -1, -1 }; + + /// + /// The Sideband Submodes gives the number of submodes possible for the + /// Sideband codec. + /// + public const int SB_SUBMODES = 8; + + /// + /// The Sideband Submodes Bits gives the number bits used to encode the + /// Sideband Submode + /// + public const int SB_SUBMODE_BITS = 3; + + /// + /// Quadratic Mirror Filter Order + /// + public const int QMF_ORDER = 64; + + #endregion + + #region Parameters + + protected internal int fullFrameSize; + protected internal float foldingGain; + + #endregion + + #region Variables + + protected internal float[] high; + protected internal float[] y0, y1; + protected internal float[] x0d; + protected internal float[] g0_mem, g1_mem; + + #endregion + + public SbCodec(bool ultraWide) + { + if (ultraWide) + { + // Initialize SubModes + submodes = BuildUwbSubModes(); + submodeID = 1; + } + else + { + // Initialize SubModes + submodes = BuildWbSubModes(); + submodeID = 3; + } + } + + protected virtual void Init( + int frameSize, int subframeSize, + int lpcSize, int bufSize, float foldingGain_0) + { + base.Init(frameSize, subframeSize, lpcSize, bufSize); + this.fullFrameSize = 2 * frameSize; + this.foldingGain = foldingGain_0; + + lag_factor = 0.002f; + + high = new float[fullFrameSize]; + y0 = new float[fullFrameSize]; + y1 = new float[fullFrameSize]; + x0d = new float[frameSize]; + g0_mem = new float[QMF_ORDER]; + g1_mem = new float[QMF_ORDER]; + } + + /// + /// Build wideband submodes. + /// + /// the wideband submodes. + protected static internal SubMode[] BuildWbSubModes() + { + // Initialize Long Term Predictions + HighLspQuant highLU = new HighLspQuant(); + // Initialize Codebook Searches + SplitShapeSearch ssCbHighLbrSearch = new SplitShapeSearch(40, 10, 4, NSpeex.Codebook_Constants.hexc_10_32_table, 5, 0); + SplitShapeSearch ssCbHighSearch = new SplitShapeSearch(40, 8, 5, NSpeex.Codebook_Constants.hexc_table, 7, 1); + // Initialize wide-band modes + SubMode[] wbSubModes = new SubMode[SB_SUBMODES]; + wbSubModes[1] = new SubMode(0, 0, 1, 0, highLU, null, null, .75f, .75f, -1, 36); + wbSubModes[2] = new SubMode(0, 0, 1, 0, highLU, null, ssCbHighLbrSearch, .85f, .6f, -1, 112); + wbSubModes[3] = new SubMode(0, 0, 1, 0, highLU, null, ssCbHighSearch, .75f, .7f, -1, 192); + wbSubModes[4] = new SubMode(0, 0, 1, 1, highLU, null, ssCbHighSearch, .75f, .75f, -1, 352); + return wbSubModes; + } + + /// + /// Build ultra-wideband submodes. + /// + /// the ultra-wideband submodes. + protected static internal SubMode[] BuildUwbSubModes() + { + /* Initialize Long Term Predictions */ + HighLspQuant highLU = new HighLspQuant(); + SubMode[] uwbSubModes = new SubMode[SB_SUBMODES]; + uwbSubModes[1] = new SubMode(0, 0, 1, 0, highLU, null, null, .75f, .75f, -1, 2); + return uwbSubModes; + } + + public override int FrameSize + { + get + { + return fullFrameSize; + } + } + + public bool Dtx + { + get + { + // TODO - should return DTX for the NbCodec + return dtx_enabled != 0; + } + } + + public override float[] Exc + { + get + { + int i; + float[] excTmp = new float[fullFrameSize]; + for (i = 0; i < frameSize; i++) + excTmp[2 * i] = 2 * excBuf[excIdx + i]; + return excTmp; + } + } + + public override float[] Innov + { + get + { + return Exc; + } + } + } +} diff --git a/Assets/Scripts/OpenTS2/NSpeex/SbCodec.cs.meta b/Assets/Scripts/OpenTS2/NSpeex/SbCodec.cs.meta new file mode 100644 index 00000000..756a47e2 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/SbCodec.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 565df4958fe8a87428811c086631c9af +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/NSpeex/SbDecoder.cs b/Assets/Scripts/OpenTS2/NSpeex/SbDecoder.cs new file mode 100644 index 00000000..184a396c --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/SbDecoder.cs @@ -0,0 +1,411 @@ +// +// Copyright (C) 2003 Jean-Marc Valin +// Copyright (C) 1999-2003 Wimba S.A., All Rights Reserved. +// Copyright (C) 2008 Filip Navara +// Copyright (C) 2009-2010 Christoph Frschl +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// - Neither the name of the Xiph.org Foundation nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +using System; +#if FIXED_POINT +using SpeexWord16 = System.Int16; +using SpeexWord32 = System.Int32; +#else +using SpeexWord16 = System.Single; +using SpeexWord32 = System.Single; +#endif + +namespace NSpeex +{ + /// + /// Sideband Speex Decoder + /// + internal class SbDecoder : SbCodec, IDecoder + { + protected internal IDecoder lowdec; + protected internal Stereo stereo; + protected internal bool enhanced; + + private float[] innov2; + + /// + /// Constructor + /// + public SbDecoder(bool ultraWide) + : base(ultraWide) + { + stereo = new Stereo(); + enhanced = true; + if (ultraWide) + Uwbinit(); + else + Wbinit(); + } + + /// + /// Wideband initialisation + /// + private void Wbinit() + { + lowdec = new NbDecoder(); + lowdec.PerceptualEnhancement = enhanced; + // Initialize variables + Init(160, 40, 8, 640, .7f); + } + + /// + /// Ultra-wideband initialisation + /// + private void Uwbinit() + { + lowdec = new SbDecoder(false); + lowdec.PerceptualEnhancement = enhanced; + // Initialize variables + Init(320, 80, 8, 1280, .5f); + } + + protected override void Init( + int frameSize, int subframeSize, + int lpcSize, int bufSize, float foldingGain) + { + base.Init(frameSize, subframeSize, lpcSize, bufSize, foldingGain); + excIdx = 0; + innov2 = new float[subframeSize]; + } + + /// + /// Decode the given input bits. + /// + /// 1 if a terminator was found, 0 if not. + public virtual int Decode(Bits bits, float[] xout) + { + int i, sub, wideband, ret; + float[] low_pi_gain, low_exc, low_innov; + + /* Decode the low-band */ + ret = lowdec.Decode(bits, x0d); + if (ret != 0) + { + return ret; + } + bool dtx = lowdec.Dtx; + if (bits == null) + { + DecodeLost(xout, dtx); + return 0; + } + /* Check "wideband bit" */ + wideband = bits.Peek(); + if (wideband != 0) + { + /* Regular wideband frame, read the submode */ + wideband = bits.Unpack(1); + submodeID = bits.Unpack(3); + } + else + { + /* was a narrowband frame, set "null submode" */ + submodeID = 0; + } + + for (i = 0; i < frameSize; i++) + excBuf[i] = 0; + + /* If null mode (no transmission), just set a couple things to zero */ + if (submodes[submodeID] == null) + { + if (dtx) + { + DecodeLost(xout, true); + return 0; + } + for (i = 0; i < frameSize; i++) + excBuf[i] = NSpeex.NbCodec.VERY_SMALL; + + first = 1; + /* Final signal synthesis from excitation */ + NSpeex.Filters.Iir_mem2(excBuf, excIdx, interp_qlpc, high, 0, + frameSize, lpcSize, mem_sp); + filters.Fir_mem_up(x0d, NSpeex.Codebook_Constants.h0, y0, + fullFrameSize, NSpeex.SbCodec.QMF_ORDER, g0_mem); + filters.Fir_mem_up(high, NSpeex.Codebook_Constants.h1, y1, + fullFrameSize, NSpeex.SbCodec.QMF_ORDER, g1_mem); + + for (i = 0; i < fullFrameSize; i++) + xout[i] = 2 * (y0[i] - y1[i]); + return 0; + } + low_pi_gain = lowdec.PiGain; + low_exc = lowdec.Exc; + low_innov = lowdec.Innov; + submodes[submodeID].LsqQuant.Unquant(qlsp, lpcSize, bits); + + if (first != 0) + { + for (i = 0; i < lpcSize; i++) + old_qlsp[i] = qlsp[i]; + } + + for (sub = 0; sub < nbSubframes; sub++) + { + float tmp, filter_ratio, el = 0.0f, rl = 0.0f, rh = 0.0f; + int subIdx = subframeSize * sub; + + /* LSP interpolation */ + tmp = (1.0f + sub) / nbSubframes; + for (i = 0; i < lpcSize; i++) + interp_qlsp[i] = (1 - tmp) * old_qlsp[i] + tmp * qlsp[i]; + + NSpeex.Lsp.Enforce_margin(interp_qlsp, lpcSize, .05f); + + /* LSPs to x-domain */ + for (i = 0; i < lpcSize; i++) + interp_qlsp[i] = (float)System.Math.Cos(interp_qlsp[i]); + + /* LSP to LPC */ + m_lsp.Lsp2lpc(interp_qlsp, interp_qlpc, lpcSize); + + if (enhanced) + { + float k1, k2, k3; + k1 = submodes[submodeID].LpcEnhK1; + k2 = submodes[submodeID].LpcEnhK2; + k3 = k1 - k2; + NSpeex.Filters.Bw_lpc(k1, interp_qlpc, awk1, lpcSize); + NSpeex.Filters.Bw_lpc(k2, interp_qlpc, awk2, lpcSize); + NSpeex.Filters.Bw_lpc(k3, interp_qlpc, awk3, lpcSize); + } + + /* + * Calculate reponse ratio between low & high filter in band middle + * (4000 Hz) + */ + tmp = 1; + pi_gain[sub] = 0; + for (i = 0; i <= lpcSize; i++) + { + rh += tmp * interp_qlpc[i]; + tmp = -tmp; + pi_gain[sub] += interp_qlpc[i]; + } + rl = low_pi_gain[sub]; + rl = 1 / (Math.Abs(rl) + .01f); + rh = 1 / (Math.Abs(rh) + .01f); + filter_ratio = Math.Abs(.01f + rh) + / (.01f + Math.Abs(rl)); + + /* reset excitation buffer */ + for (i = subIdx; i < subIdx + subframeSize; i++) + excBuf[i] = 0; + + if (submodes[submodeID].Innovation == null) + { + float g; + int quant; + + quant = bits.Unpack(5); + g = (float)Math.Exp(((double)quant - 10) / 8.0d); + g /= filter_ratio; + + /* High-band excitation using the low-band excitation and a gain */ + for (i = subIdx; i < subIdx + subframeSize; i++) + excBuf[i] = foldingGain * g * low_innov[i]; + } + else + { + float gc, scale; + int qgc = bits.Unpack(4); + + for (i = subIdx; i < subIdx + subframeSize; i++) + el += low_exc[i] * low_exc[i]; + + gc = (float)Math.Exp((1 / 3.7f) * qgc - 2); + scale = gc * (float)Math.Sqrt(1 + el) / filter_ratio; + submodes[submodeID].Innovation.Unquantify(excBuf, subIdx, + subframeSize, bits); + + for (i = subIdx; i < subIdx + subframeSize; i++) + excBuf[i] *= scale; + + if (submodes[submodeID].DoubleCodebook != 0) + { + for (i = 0; i < subframeSize; i++) + innov2[i] = 0; + submodes[submodeID].Innovation.Unquantify(innov2, 0, + subframeSize, bits); + for (i = 0; i < subframeSize; i++) + innov2[i] *= scale * (1 / 2.5f); + for (i = 0; i < subframeSize; i++) + excBuf[subIdx + i] += innov2[i]; + } + } + + for (i = subIdx; i < subIdx + subframeSize; i++) + high[i] = excBuf[i]; + + if (enhanced) + { + /* Use enhanced LPC filter */ + NSpeex.Filters.Filter_mem2(high, subIdx, awk2, awk1, + subframeSize, lpcSize, mem_sp, lpcSize); + NSpeex.Filters.Filter_mem2(high, subIdx, awk3, interp_qlpc, + subframeSize, lpcSize, mem_sp, 0); + } + else + { + /* Use regular filter */ + for (i = 0; i < lpcSize; i++) + mem_sp[lpcSize + i] = 0; + NSpeex.Filters.Iir_mem2(high, subIdx, interp_qlpc, high, subIdx, + subframeSize, lpcSize, mem_sp); + } + } + + filters.Fir_mem_up(x0d, NSpeex.Codebook_Constants.h0, y0, fullFrameSize, + NSpeex.SbCodec.QMF_ORDER, g0_mem); + filters.Fir_mem_up(high, NSpeex.Codebook_Constants.h1, y1, + fullFrameSize, NSpeex.SbCodec.QMF_ORDER, g1_mem); + + for (i = 0; i < fullFrameSize; i++) + xout[i] = 2 * (y0[i] - y1[i]); + + for (i = 0; i < lpcSize; i++) + old_qlsp[i] = qlsp[i]; + + first = 0; + return 0; + } + + /// + /// Decode when packets are lost. + /// + /// 0 if successful. + public int DecodeLost(float[] xout, bool dtx) + { + int i; + int saved_modeid = 0; + + if (dtx) + { + saved_modeid = submodeID; + submodeID = 1; + } + else + { + NSpeex.Filters.Bw_lpc(0.99f, interp_qlpc, interp_qlpc, lpcSize); + } + + first = 1; + awk1 = new float[lpcSize + 1]; + awk2 = new float[lpcSize + 1]; + awk3 = new float[lpcSize + 1]; + + if (enhanced) + { + float k1, k2, k3; + if (submodes[submodeID] != null) + { + k1 = submodes[submodeID].LpcEnhK1; + k2 = submodes[submodeID].LpcEnhK2; + } + else + { + k1 = k2 = 0.7f; + } + k3 = k1 - k2; + NSpeex.Filters.Bw_lpc(k1, interp_qlpc, awk1, lpcSize); + NSpeex.Filters.Bw_lpc(k2, interp_qlpc, awk2, lpcSize); + NSpeex.Filters.Bw_lpc(k3, interp_qlpc, awk3, lpcSize); + } + + /* Final signal synthesis from excitation */ + if (!dtx) + { + for (i = 0; i < frameSize; i++) + excBuf[excIdx + i] *= ((Single?).9d).Value; + } + for (i = 0; i < frameSize; i++) + high[i] = excBuf[excIdx + i]; + + if (enhanced) + { + /* Use enhanced LPC filter */ + NSpeex.Filters.Filter_mem2(high, 0, awk2, awk1, high, 0, frameSize, + lpcSize, mem_sp, lpcSize); + NSpeex.Filters.Filter_mem2(high, 0, awk3, interp_qlpc, high, 0, + frameSize, lpcSize, mem_sp, 0); + } + else + { /* Use regular filter */ + for (i = 0; i < lpcSize; i++) + mem_sp[lpcSize + i] = 0; + NSpeex.Filters.Iir_mem2(high, 0, interp_qlpc, high, 0, frameSize, + lpcSize, mem_sp); + } + /* + * iir_mem2(st->exc, st->interp_qlpc, st->high, st->frame_size, + * st->lpcSize, st->mem_sp); + */ + + /* Reconstruct the original */ + filters.Fir_mem_up(x0d, NSpeex.Codebook_Constants.h0, y0, fullFrameSize, + NSpeex.SbCodec.QMF_ORDER, g0_mem); + filters.Fir_mem_up(high, NSpeex.Codebook_Constants.h1, y1, + fullFrameSize, NSpeex.SbCodec.QMF_ORDER, g1_mem); + for (i = 0; i < fullFrameSize; i++) + xout[i] = 2 * (y0[i] - y1[i]); + + if (dtx) + { + submodeID = saved_modeid; + } + return 0; + } + + /// + /// Decode the given bits to stereo. + /// + public virtual void DecodeStereo(float[] data, int frameSize) + { + stereo.Decode(data, frameSize); + } + + public virtual bool PerceptualEnhancement + { + get + { + return enhanced; + } + set + { + this.enhanced = value; + } + } + } +} diff --git a/Assets/Scripts/OpenTS2/NSpeex/SbDecoder.cs.meta b/Assets/Scripts/OpenTS2/NSpeex/SbDecoder.cs.meta new file mode 100644 index 00000000..6704513d --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/SbDecoder.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 61068bf9da2442a4697894d344259b14 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/NSpeex/SbEncoder.cs b/Assets/Scripts/OpenTS2/NSpeex/SbEncoder.cs new file mode 100644 index 00000000..e09605e3 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/SbEncoder.cs @@ -0,0 +1,896 @@ +// +// Copyright (C) 2003 Jean-Marc Valin +// Copyright (C) 1999-2003 Wimba S.A., All Rights Reserved. +// Copyright (C) 2008 Filip Navara +// Copyright (C) 2009-2010 Christoph Frschl +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// - Neither the name of the Xiph.org Foundation nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +using System; + +namespace NSpeex +{ + /// + /// Wideband Speex Encoder + /// + internal class SbEncoder : SbCodec, IEncoder + { + /// + /// The Narrowband Quality map indicates which narrowband submode to use for + /// the given wideband/ultra-wideband quality setting + /// + private static readonly int[] NB_QUALITY_MAP = { 1, 8, 2, 3, 4, 5, 5, 6, 6, 7, 7 }; + + /// + /// The Wideband Quality map indicates which sideband submode to use for the + /// given wideband/ultra-wideband quality setting + /// + private static readonly int[] WB_QUALITY_MAP = { 1, 1, 1, 1, 1, 1, 2, 2, 3, 3, 4 }; + + /// + /// The Ultra-wideband Quality map indicates which sideband submode to use + /// for the given ultra-wideband quality setting + /// + /// + private static readonly int[] UWB_QUALITY_MAP = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; + + /// + /// The encoder for the lower half of the Spectrum. + /// + protected internal IEncoder lowenc; + + private float[] x1d; + private float[] h0_mem; + + private float[] buf; + private float[] swBuf; + /// + /// Weighted signal buffer + /// + /// + private float[] res; + private float[] target; + private float[] window; + private float[] lagWindow; + + private float[] rc; + /// + /// Reflection coefficients + /// + private float[] autocorr; + /// + /// auto-correlation + /// + private float[] lsp; + /// + /// LSPs for current frame + /// + private float[] old_lsp; + /// + /// LSPs for previous frame + /// + private float[] interp_lsp; + /// + /// Interpolated LSPs + /// + private float[] interp_lpc; + /// + /// Interpolated LPCs + /// + private float[] bw_lpc1; + /// + /// LPCs after bandwidth expansion by gamma1 for perceptual weighting + /// + private float[] bw_lpc2; + /// + /// LPCs after bandwidth expansion by gamma2 for perceptual weighting + /// + + private float[] mem_sp2; + private float[] mem_sw; + /** Filter memory for perceptually-weighted signal */ + + protected internal int nb_modes; + + private bool uwb; + + protected internal int complexity; + /// + /// Complexity setting (0-10 from least complex to most complex) + /// + protected internal int vbr_enabled; + /// + /// 1 for enabling VBR, 0 otherwise + /// + protected internal int vad_enabled; + /// + /// 1 for enabling VAD, 0 otherwise + /// + protected internal int abr_enabled; + /// + /// ABR setting (in bps), 0 if off + /// + protected internal float vbr_quality; + /// + /// Quality setting for VBR encoding + /// + protected internal float relative_quality; + /// + /// Relative quality that will be needed by VBR + /// + protected internal float abr_drift; + protected internal float abr_drift2; + protected internal float abr_count; + protected internal int sampling_rate; + + protected internal int submodeSelect; + + /** Mode chosen by the user (may differ from submodeID if VAD is on) */ + + public SbEncoder(bool ultraWide) + : base(ultraWide) + { + if (ultraWide) + Uwbinit(); + else + Wbinit(); + } + + /// + /// Wideband initialisation + /// + private void Wbinit() + { + lowenc = new NbEncoder(); + // Initialize variables + Init(160, 40, 8, 640, .9f); + uwb = false; + nb_modes = 5; + sampling_rate = 16000; + } + + /// + /// Ultra-wideband initialisation + /// + private void Uwbinit() + { + lowenc = new SbEncoder(false); + // Initialize variables + Init(320, 80, 8, 1280, .7f); + uwb = true; + nb_modes = 2; + sampling_rate = 32000; + } + + protected override void Init( + int frameSize, int subframeSize, + int lpcSize, int bufSize, float foldingGain) + { + base.Init(frameSize, subframeSize, lpcSize, bufSize, foldingGain); + + complexity = 3; // in C it's 2 here, but set to 3 automatically by the + // encoder + vbr_enabled = 0; // disabled by default + vad_enabled = 0; // disabled by default + abr_enabled = 0; // disabled by default + vbr_quality = 8; + + submodeSelect = submodeID; + + x1d = new float[frameSize]; + h0_mem = new float[NSpeex.SbCodec.QMF_ORDER]; + buf = new float[windowSize]; + swBuf = new float[frameSize]; + res = new float[frameSize]; + target = new float[subframeSize]; + + window = NSpeex.Misc.Window(windowSize, subframeSize); + lagWindow = NSpeex.Misc.LagWindow(lpcSize, lag_factor); + + rc = new float[lpcSize]; + autocorr = new float[lpcSize + 1]; + lsp = new float[lpcSize]; + old_lsp = new float[lpcSize]; + interp_lsp = new float[lpcSize]; + interp_lpc = new float[lpcSize + 1]; + bw_lpc1 = new float[lpcSize + 1]; + bw_lpc2 = new float[lpcSize + 1]; + + mem_sp2 = new float[lpcSize]; + mem_sw = new float[lpcSize]; + + abr_count = 0; + } + + /// + /// Encode the given input signal. + /// + /// 1 if successful. + public virtual int Encode(Bits bits, float[] ins0) + { + int i; + float[] mem, innov, syn_resp; + float[] low_pi_gain, low_exc, low_innov; + int dtx; + + /* Compute the two sub-bands by filtering with h0 and h1 */ + NSpeex.Filters.Qmf_decomp(ins0, NSpeex.Codebook_Constants.h0, x0d, x1d, + fullFrameSize, NSpeex.SbCodec.QMF_ORDER, h0_mem); + /* Encode the narrowband part */ + lowenc.Encode(bits, x0d); + + /* High-band buffering / sync with low band */ + for (i = 0; i < windowSize - frameSize; i++) + high[i] = high[frameSize + i]; + for (i = 0; i < frameSize; i++) + high[windowSize - frameSize + i] = x1d[i]; + + System.Array.Copy(excBuf, frameSize, excBuf, 0, bufSize + - frameSize); + + low_pi_gain = lowenc.PiGain; + low_exc = lowenc.Exc; + low_innov = lowenc.Innov; + + int low_mode = lowenc.Mode; + if (low_mode == 0) + dtx = 1; + else + dtx = 0; + + /* Start encoding the high-band */ + for (i = 0; i < windowSize; i++) + buf[i] = high[i] * window[i]; + + /* Compute auto-correlation */ + NSpeex.Lpc.Autocorr(buf, autocorr, lpcSize + 1, windowSize); + + autocorr[0] += 1; /* prevents NANs */ + autocorr[0] *= lpc_floor; /* Noise floor in auto-correlation domain */ + /* Lag windowing: equivalent to filtering in the power-spectrum domain */ + for (i = 0; i < lpcSize + 1; i++) + autocorr[i] *= lagWindow[i]; + + /* Levinson-Durbin */ + NSpeex.Lpc.Wld(lpc, autocorr, rc, lpcSize); // tmperr + System.Array.Copy(lpc, 0, lpc, 1, lpcSize); + lpc[0] = 1; + + /* LPC to LSPs (x-domain) transform */ + int roots = NSpeex.Lsp.Lpc2lsp(lpc, lpcSize, lsp, 15, 0.2f); + if (roots != lpcSize) + { + roots = NSpeex.Lsp.Lpc2lsp(lpc, lpcSize, lsp, 11, 0.02f); + if (roots != lpcSize) + { + /* + * If we can't find all LSP's, do some damage control and use a + * flat filter + */ + for (i = 0; i < lpcSize; i++) + { + lsp[i] = (float)System.Math.Cos(System.Math.PI + * ((float)(i + 1)) / (lpcSize + 1)); + } + } + } + + /* x-domain to angle domain */ + for (i = 0; i < lpcSize; i++) + lsp[i] = (float)System.Math.Acos(lsp[i]); + + float lsp_dist = 0; + for (i = 0; i < lpcSize; i++) + lsp_dist += (old_lsp[i] - lsp[i]) * (old_lsp[i] - lsp[i]); + + /* VBR stuff */ + if ((vbr_enabled != 0 || vad_enabled != 0) && dtx == 0) + { + float e_low = 0, e_high = 0; + float ratio; + if (abr_enabled != 0) + { + float qual_change = 0; + if (abr_drift2 * abr_drift > 0) + { + /* + * Only adapt if long-term and short-term drift are the same + * sign + */ + qual_change = -.00001f * abr_drift / (1 + abr_count); + if (qual_change > .1f) + qual_change = .1f; + if (qual_change < -.1f) + qual_change = -.1f; + } + vbr_quality += qual_change; + if (vbr_quality > 10) + vbr_quality = 10; + if (vbr_quality < 0) + vbr_quality = 0; + } + + for (i = 0; i < frameSize; i++) + { + e_low += x0d[i] * x0d[i]; + e_high += high[i] * high[i]; + } + ratio = (float)Math.Log((1 + e_high) / (1 + e_low)); + relative_quality = lowenc.RelativeQuality; + + if (ratio < -4) + ratio = -4; + if (ratio > 2) + ratio = 2; + /* if (ratio>-2) */ + if (vbr_enabled != 0) + { + int modeid; + modeid = nb_modes - 1; + relative_quality += 1.0f * (ratio + 2); + if (relative_quality < -1) + { + relative_quality = -1; + } + while (modeid != 0) + { + int v1; + float thresh; + v1 = (int)Math.Floor(vbr_quality); + if (v1 == 10) + thresh = NSpeex.Vbr.hb_thresh[modeid][v1]; + else + thresh = (vbr_quality - v1) + * NSpeex.Vbr.hb_thresh[modeid][v1 + 1] + + (1 + v1 - vbr_quality) + * NSpeex.Vbr.hb_thresh[modeid][v1]; + if (relative_quality >= thresh) + break; + modeid--; + } + Mode = modeid; + if (abr_enabled != 0) + { + int bitrate; + bitrate = BitRate; + abr_drift += (bitrate - abr_enabled); + abr_drift2 = .95f * abr_drift2 + .05f + * (bitrate - abr_enabled); + abr_count += 1.0f; + } + } + else + { + /* VAD only */ + int modeid_0; + if (relative_quality < 2.0d) + modeid_0 = 1; + else + modeid_0 = submodeSelect; + /* speex_encoder_ctl(state, SPEEX_SET_MODE, &mode); */ + submodeID = modeid_0; + + } + /* fprintf (stderr, "%f %f\n", ratio, low_qual); */ + } + + bits.Pack(1, 1); + if (dtx != 0) + bits.Pack(0, NSpeex.SbCodec.SB_SUBMODE_BITS); + else + bits.Pack(submodeID, NSpeex.SbCodec.SB_SUBMODE_BITS); + + /* If null mode (no transmission), just set a couple things to zero */ + if (dtx != 0 || submodes[submodeID] == null) + { + for (i = 0; i < frameSize; i++) + excBuf[excIdx + i] = swBuf[i] = NSpeex.NbCodec.VERY_SMALL; + + for (i = 0; i < lpcSize; i++) + mem_sw[i] = 0; + first = 1; + + /* Final signal synthesis from excitation */ + NSpeex.Filters.Iir_mem2(excBuf, excIdx, interp_qlpc, high, 0, + subframeSize, lpcSize, mem_sp); + + /* Reconstruct the original */ + filters.Fir_mem_up(x0d, NSpeex.Codebook_Constants.h0, y0, + fullFrameSize, NSpeex.SbCodec.QMF_ORDER, g0_mem); + filters.Fir_mem_up(high, NSpeex.Codebook_Constants.h1, y1, + fullFrameSize, NSpeex.SbCodec.QMF_ORDER, g1_mem); + + for (i = 0; i < fullFrameSize; i++) + ins0[i] = 2 * (y0[i] - y1[i]); + + if (dtx != 0) + return 0; + else + return 1; + } + + /* LSP quantization */ + submodes[submodeID].LsqQuant.Quant(lsp, qlsp, lpcSize, bits); + + if (first != 0) + { + for (i = 0; i < lpcSize; i++) + old_lsp[i] = lsp[i]; + for (i = 0; i < lpcSize; i++) + old_qlsp[i] = qlsp[i]; + } + + mem = new float[lpcSize]; + syn_resp = new float[subframeSize]; + innov = new float[subframeSize]; + + for (int sub = 0; sub < nbSubframes; sub++) + { + float tmp, filter_ratio; + int exc, sp, sw, resp; + int offset; + float rl, rh, eh = 0, el = 0; + int fold; + + offset = subframeSize * sub; + sp = offset; + exc = excIdx + offset; + resp = offset; + sw = offset; + + /* LSP interpolation (quantized and unquantized) */ + tmp = (1.0f + sub) / nbSubframes; + for (i = 0; i < lpcSize; i++) + interp_lsp[i] = (1 - tmp) * old_lsp[i] + tmp * lsp[i]; + for (i = 0; i < lpcSize; i++) + interp_qlsp[i] = (1 - tmp) * old_qlsp[i] + tmp * qlsp[i]; + + NSpeex.Lsp.Enforce_margin(interp_lsp, lpcSize, .05f); + NSpeex.Lsp.Enforce_margin(interp_qlsp, lpcSize, .05f); + + /* Compute interpolated LPCs (quantized and unquantized) */ + for (i = 0; i < lpcSize; i++) + interp_lsp[i] = (float)System.Math.Cos(interp_lsp[i]); + for (i = 0; i < lpcSize; i++) + interp_qlsp[i] = (float)System.Math.Cos(interp_qlsp[i]); + + m_lsp.Lsp2lpc(interp_lsp, interp_lpc, lpcSize); + m_lsp.Lsp2lpc(interp_qlsp, interp_qlpc, lpcSize); + + NSpeex.Filters.Bw_lpc(gamma1, interp_lpc, bw_lpc1, lpcSize); + NSpeex.Filters.Bw_lpc(gamma2, interp_lpc, bw_lpc2, lpcSize); + + /* + * Compute mid-band (4000 Hz for wideband) response of low-band and + * high-band filters + */ + rl = rh = 0; + tmp = 1; + pi_gain[sub] = 0; + for (i = 0; i <= lpcSize; i++) + { + rh += tmp * interp_qlpc[i]; + tmp = -tmp; + pi_gain[sub] += interp_qlpc[i]; + } + rl = low_pi_gain[sub]; + rl = 1 / (Math.Abs(rl) + .01f); + rh = 1 / (Math.Abs(rh) + .01f); + /* Compute ratio, will help predict the gain */ + filter_ratio = Math.Abs(.01f + rh) + / (.01f + Math.Abs(rl)); + + fold = (filter_ratio < 5) ? 1 : 0; + /* printf ("filter_ratio %f\n", filter_ratio); */ + fold = 0; + + /* Compute "real excitation" */ + NSpeex.Filters.Fir_mem2(high, sp, interp_qlpc, excBuf, exc, + subframeSize, lpcSize, mem_sp2); + /* Compute energy of low-band and high-band excitation */ + for (i = 0; i < subframeSize; i++) + eh += excBuf[exc + i] * excBuf[exc + i]; + + if (submodes[submodeID].Innovation == null) + {/* + * 1 for spectral + * folding + * excitation, 0 for + * stochastic + */ + float g; + /* speex_bits_pack(bits, 1, 1); */ + for (i = 0; i < subframeSize; i++) + el += low_innov[offset + i] * low_innov[offset + i]; + + /* + * Gain to use if we want to use the low-band excitation for + * high-band + */ + g = eh / (.01f + el); + g = (float)Math.Sqrt(g); + + g *= filter_ratio; + /* print_vec(&g, 1, "gain factor"); */ + /* Gain quantization */ + { + int quant = (int)Math.Floor(.5d + 10 + 8.0d * Math.Log((g + .0001d))); + /* speex_warning_int("tata", quant); */ + if (quant < 0) + quant = 0; + if (quant > 31) + quant = 31; + bits.Pack(quant, 5); + g = (float)(.1d * Math.Exp(quant / 9.4d)); + } + /* printf ("folding gain: %f\n", g); */ + g /= filter_ratio; + + } + else + { + float gc, scale, scale_1; + + for (i = 0; i < subframeSize; i++) + el += low_exc[offset + i] * low_exc[offset + i]; + /* speex_bits_pack(bits, 0, 1); */ + + gc = (float)(Math.Sqrt(1 + eh) * filter_ratio / Math.Sqrt((1 + el) * subframeSize)); + { + int qgc = (int)Math.Floor(.5d + 3.7d * (Math.Log(gc) + 2)); + if (qgc < 0) + qgc = 0; + if (qgc > 15) + qgc = 15; + bits.Pack(qgc, 4); + gc = (float)Math.Exp((1 / 3.7d) * qgc - 2); + } + + scale = gc * (float)Math.Sqrt(1 + el) / filter_ratio; + scale_1 = 1 / scale; + + for (i = 0; i < subframeSize; i++) + excBuf[exc + i] = 0; + excBuf[exc] = 1; + NSpeex.Filters.Syn_percep_zero(excBuf, exc, interp_qlpc, + bw_lpc1, bw_lpc2, syn_resp, subframeSize, lpcSize); + + /* Reset excitation */ + for (i = 0; i < subframeSize; i++) + excBuf[exc + i] = 0; + + /* + * Compute zero response (ringing) of A(z/g1) / ( A(z/g2) * + * Aq(z) ) + */ + for (i = 0; i < lpcSize; i++) + mem[i] = mem_sp[i]; + NSpeex.Filters.Iir_mem2(excBuf, exc, interp_qlpc, excBuf, exc, + subframeSize, lpcSize, mem); + + for (i = 0; i < lpcSize; i++) + mem[i] = mem_sw[i]; + NSpeex.Filters.Filter_mem2(excBuf, exc, bw_lpc1, bw_lpc2, res, + resp, subframeSize, lpcSize, mem, 0); + + /* Compute weighted signal */ + for (i = 0; i < lpcSize; i++) + mem[i] = mem_sw[i]; + NSpeex.Filters.Filter_mem2(high, sp, bw_lpc1, bw_lpc2, swBuf, + sw, subframeSize, lpcSize, mem, 0); + + /* Compute target signal */ + for (i = 0; i < subframeSize; i++) + target[i] = swBuf[sw + i] - res[resp + i]; + + for (i = 0; i < subframeSize; i++) + excBuf[exc + i] = 0; + + for (i = 0; i < subframeSize; i++) + target[i] *= scale_1; + + /* Reset excitation */ + for (i = 0; i < subframeSize; i++) + innov[i] = 0; + + /* print_vec(target, st->subframeSize, "\ntarget"); */ + submodes[submodeID].Innovation.Quantify(target, interp_qlpc, + bw_lpc1, bw_lpc2, lpcSize, subframeSize, innov, 0, + syn_resp, bits, (complexity + 1) >> 1); + /* print_vec(target, st->subframeSize, "after"); */ + + for (i = 0; i < subframeSize; i++) + excBuf[exc + i] += innov[i] * scale; + + if (submodes[submodeID].DoubleCodebook != 0) + { + float[] innov2 = new float[subframeSize]; + for (i = 0; i < subframeSize; i++) + innov2[i] = 0; + for (i = 0; i < subframeSize; i++) + target[i] *= 2.5f; + submodes[submodeID].Innovation.Quantify(target, interp_qlpc, + bw_lpc1, bw_lpc2, lpcSize, subframeSize, innov2, 0, + syn_resp, bits, (complexity + 1) >> 1); + for (i = 0; i < subframeSize; i++) + innov2[i] *= (float)(scale * (1 / 2.5d)); + for (i = 0; i < subframeSize; i++) + excBuf[exc + i] += innov2[i]; + } + } + + /* Keep the previous memory */ + for (i = 0; i < lpcSize; i++) + mem[i] = mem_sp[i]; + /* Final signal synthesis from excitation */ + NSpeex.Filters.Iir_mem2(excBuf, exc, interp_qlpc, high, sp, + subframeSize, lpcSize, mem_sp); + + /* + * Compute weighted signal again, from synthesized speech (not sure + * it's the right thing) + */ + NSpeex.Filters.Filter_mem2(high, sp, bw_lpc1, bw_lpc2, swBuf, sw, + subframeSize, lpcSize, mem_sw, 0); + } + + // #ifndef RELEASE + /* Reconstruct the original */ + filters.Fir_mem_up(x0d, NSpeex.Codebook_Constants.h0, y0, fullFrameSize, + NSpeex.SbCodec.QMF_ORDER, g0_mem); + filters.Fir_mem_up(high, NSpeex.Codebook_Constants.h1, y1, + fullFrameSize, NSpeex.SbCodec.QMF_ORDER, g1_mem); + + for (i = 0; i < fullFrameSize; i++) + ins0[i] = 2 * (y0[i] - y1[i]); + // #endif + for (i = 0; i < lpcSize; i++) + old_lsp[i] = lsp[i]; + for (i = 0; i < lpcSize; i++) + old_qlsp[i] = qlsp[i]; + first = 0; + return 1; + } + + public virtual int EncodedFrameSize + { + get + { + int size = NSpeex.SbCodec.SB_FRAME_SIZE[submodeID]; + size += lowenc.EncodedFrameSize; + return size; + } + } + + public virtual int Quality + { + set + { + if (value < 0) + value = 0; + if (value > 10) + value = 10; + if (uwb) + { + lowenc.Quality = value; + this.Mode = UWB_QUALITY_MAP[value]; + } + else + { + lowenc.Mode = NB_QUALITY_MAP[value]; + this.Mode = WB_QUALITY_MAP[value]; + } + } + } + + + public virtual int BitRate + { + get + { + if (submodes[submodeID] != null) + return lowenc.BitRate + sampling_rate + * submodes[submodeID].BitsPerFrame / frameSize; + else + return lowenc.BitRate + sampling_rate + * (NSpeex.SbCodec.SB_SUBMODE_BITS + 1) / frameSize; + } + set + { + for (int i = 10; i >= 0; i--) + { + Quality = i; + if (BitRate <= value) + return; + } + } + } + + + public virtual int LookAhead + { + get + { + return 2 * lowenc.LookAhead + NSpeex.SbCodec.QMF_ORDER - 1; + } + } + + + public virtual int Mode + { + get + { + return submodeID; + } + set + { + if (value < 0) + { + value = 0; + } + submodeID = submodeSelect = value; + } + } + + public virtual bool Vbr + { + get + { + return vbr_enabled != 0; + } + set + { + // super.setVbr(vbr); + vbr_enabled = (value) ? 1 : 0; + lowenc.Vbr = value; + } + } + + public virtual bool Vad + { + get + { + return vad_enabled != 0; + } + set + { + vad_enabled = (value) ? 1 : 0; + } + } + + public new bool Dtx + { + get + { + return dtx_enabled == 1; + } + set + { + dtx_enabled = (value) ? 1 : 0; + } + } + + public virtual int Abr + { + get + { + return abr_enabled; + } + set + { + lowenc.Vbr = true; + // super.setAbr(abr); + abr_enabled = (value != 0) ? 1 : 0; + vbr_enabled = 1; + { + int i = 10, rate, target_0; + float vbr_qual; + target_0 = value; + while (i >= 0) + { + Quality = i; + rate = BitRate; + if (rate <= target_0) + break; + i--; + } + vbr_qual = i; + if (vbr_qual < 0) + vbr_qual = 0; + VbrQuality = vbr_qual; + abr_count = 0; + abr_drift = 0; + abr_drift2 = 0; + } + } + } + + + public virtual float VbrQuality + { + get + { + return vbr_quality; + } + set + { + vbr_quality = value; + float qual = value + 0.6f; + if (qual > 10) + qual = 10; + lowenc.VbrQuality = qual; + int q = (int)Math.Floor(.5d + value); + if (q > 10) + q = 10; + Quality = q; + } + } + + + public virtual int Complexity + { + get + { + return complexity; + } + set + { + if (value < 0) + value = 0; + if (value > 10) + value = 10; + this.complexity = value; + } + } + + + public virtual int SamplingRate + { + get + { + return sampling_rate; + } + set + { + // super.setSamplingRate(rate); + sampling_rate = value; + lowenc.SamplingRate = value; + } + } + + + public virtual float RelativeQuality + { + get + { + return relative_quality; + } + } + } +} diff --git a/Assets/Scripts/OpenTS2/NSpeex/SbEncoder.cs.meta b/Assets/Scripts/OpenTS2/NSpeex/SbEncoder.cs.meta new file mode 100644 index 00000000..1312297f --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/SbEncoder.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 16d1324c8a0564f47b2bf59203770079 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/NSpeex/SpeexDecoder.cs b/Assets/Scripts/OpenTS2/NSpeex/SpeexDecoder.cs new file mode 100644 index 00000000..9be0eb68 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/SpeexDecoder.cs @@ -0,0 +1,163 @@ +// +// Copyright (C) 2009-2010 Christoph Frschl +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// - Neither the name of the Xiph.org Foundation nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +using System; + +namespace NSpeex +{ + /// + /// NSpeex Decoder class. This class decodes the given speex frames into + /// PCM 16bit samples. + /// + public class SpeexDecoder + { + private readonly int sampleRate; + private float[] decodedData; + private readonly Bits bits; + private readonly IDecoder decoder; + private readonly int frameSize; + + /// + /// Constructor + /// The mode of the decoder. + /// Whether to enable perceptual enhancement or not. + /// + public SpeexDecoder(BandMode mode, bool enhanced = true) + { + bits = new Bits(); + switch (mode) + { + case BandMode.Narrow: + decoder = new NbDecoder(); + sampleRate = 8000; + break; + // Wideband + case BandMode.Wide: + decoder = new SbDecoder(false); + sampleRate = 16000; + break; + case BandMode.UltraWide: + decoder = new SbDecoder(true); + sampleRate = 32000; + break; + // */ + default: + decoder = new NbDecoder(); + sampleRate = 8000; + break; + } + + /* initialize the speex decoder */ + decoder.PerceptualEnhancement = enhanced; + /* set decoder format and properties */ + frameSize = decoder.FrameSize; + decodedData = new float[sampleRate * 2]; // init buffer to 1 second + } + + /// + /// The frame size indicates the samples which are packed in a single Speex frame. + /// + public int FrameSize + { + get + { + return decoder.FrameSize; + } + } + + /// + /// The sampling rate in samples per second + /// + public int SampleRate + { + get + { + return sampleRate; + } + } + + /// + /// Decodes the given encoded data. + /// + /// The encoded data. Can be multiple frames. + /// Start offset where to read the encoded data from. + /// The number of bytes to decode. + /// The output of the decoded data in samples. + /// Start offset where to start writing the decoded samples from. + /// Indicates if we are decoding a lost frame. Alternatively the parameter can be null. + /// The number of samples decoded. + public int Decode(byte[] inData, int inOffset, int inCount, short[] outData, int outOffset, bool lostFrame) + { + if (decodedData.Length < outData.Length * 2) + { + // resize the decoded data buffer + decodedData = new float[outData.Length * 2]; + } + + if (lostFrame || inData == null) + { + decoder.Decode(null, decodedData); + for (int i = 0; i < frameSize; i++, outOffset++) + { + outData[outOffset] = ConvertToShort(decodedData[i]); + } + return frameSize; + } + + bits.ReadFrom(inData, inOffset, inCount); + int samplesDecoded = 0; + while (decoder.Decode(bits, decodedData) == 0) + { + for (int i = 0; i < frameSize; i++, outOffset++) + { + + outData[outOffset] = ConvertToShort(decodedData[i]); + } + samplesDecoded += frameSize; + } + + return samplesDecoded; + } + + + private static short ConvertToShort(float value) + { + // PCM saturation + if (value > 32767.0f) + value = 32767.0f; + else if (value < -32768.0f) + value = -32768.0f; + + // Convert to short and save to buffer + return (short)Math.Round(value); + } + } +} diff --git a/Assets/Scripts/OpenTS2/NSpeex/SpeexDecoder.cs.meta b/Assets/Scripts/OpenTS2/NSpeex/SpeexDecoder.cs.meta new file mode 100644 index 00000000..e719f8d8 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/SpeexDecoder.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1fc51c282c64d1b4982e77d8aa9bdbef +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/NSpeex/SpeexEncoder.cs b/Assets/Scripts/OpenTS2/NSpeex/SpeexEncoder.cs new file mode 100644 index 00000000..9698b38e --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/SpeexEncoder.cs @@ -0,0 +1,160 @@ +// +// Copyright (C) 2009-2010 Christoph Frschl +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// - Neither the name of the Xiph.org Foundation nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +using System; + +namespace NSpeex +{ + /// + /// NSpeex Encoder class. This class encodes the given PCM 16bit samples into speex + /// frames. + /// + public class SpeexEncoder + { + /// + /// Version of the Speex Encoder + /// + public const String Version = ".Net Speex Encoder v0.0.1"; + + private readonly IEncoder encoder; + private readonly Bits bits; + private readonly float[] rawData; + private readonly int frameSize; + + /// + /// Constructor + /// + /// the mode of the encoder (0=NB, 1=WB, 2=UWB). + /// true if initialisation successful. + public SpeexEncoder(BandMode mode) + { + bits = new Bits(); + switch (mode) + { + case BandMode.Narrow: + encoder = new NbEncoder(); + break; + case BandMode.Wide: + encoder = new SbEncoder(false); + break; + case BandMode.UltraWide: + encoder = new SbEncoder(true); + break; + default: + throw new ArgumentException("Invalid mode", "mode"); + } + + /* set decoder format and properties */ + frameSize = encoder.FrameSize; + rawData = new float[frameSize]; + } + + /// + /// The sampling rate in samples per second + /// + public int SampleRate + { + get + { + return encoder.SamplingRate; + } + } + + /// + /// The encoder quality within the range [0-10]. + /// + public int Quality + { + set + { + encoder.Quality = value; + } + } + + /// + /// Turns encoding in variable bit rate on or off. + /// + public bool VBR + { + get + { + return encoder.Vbr; + } + + set + { + encoder.Vbr = value; + } + } + + /// + /// The frame size indicates the samples which are packed in a single Speex frame. + /// + public int FrameSize + { + get + { + return frameSize; + } + } + + /// + /// Encodes the given sample data. + /// + /// Array of samples. + /// Start offset for the inData. + /// Number of samples to encode. Must be a multiple of . + /// The encoded data. + /// Start offset when writing to outData + /// The length of the outData array (maximum number of bytes writting after encoding). + /// The bytes encoded. + public int Encode(short[] inData, int inOffset, int inCount, byte[] outData, int outOffset, int outCount) + { + bits.Reset(); + int samplesProcessed = 0; + int result = 0; + while (samplesProcessed < inCount) + { + // convert shorts into float samples, + for (int i = 0; i < frameSize; i++) + rawData[i] = inData[inOffset + i + samplesProcessed]; + + result += encoder.Encode(bits, rawData); + samplesProcessed += frameSize; + } + + if (result == 0) + return 0; + + return bits.Write(outData, outOffset, outCount); + } + } +} diff --git a/Assets/Scripts/OpenTS2/NSpeex/SpeexEncoder.cs.meta b/Assets/Scripts/OpenTS2/NSpeex/SpeexEncoder.cs.meta new file mode 100644 index 00000000..cb9a7e44 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/SpeexEncoder.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ca51c2b2282acd3439cef5e486c737fe +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/NSpeex/SpeexFrame.cs b/Assets/Scripts/OpenTS2/NSpeex/SpeexFrame.cs new file mode 100644 index 00000000..9aa41cc3 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/SpeexFrame.cs @@ -0,0 +1,32 @@ +using System; + +namespace NSpeex +{ + public class SpeexFrame + { + public const int FRAME_MAX_SIZE = 160;//size must less than 160 in byte + private byte[] mData; + private int mSize; + public SpeexFrame(byte[] data, int size) + { + this.mData = new byte[size]; + Array.Copy(data, 0, this.mData, 0, size); + this.mSize = size; + } + public byte[] Data + { + get { return mData; } + } + public int Size + { + get { return mSize; } + } + public static SpeexFrame ParseFrom(byte[] buf, int offset, int size) + { + byte[] data = new byte[size]; + Array.Copy(buf, offset, data, 0, size); + return new SpeexFrame(data, size); + } + + } +} diff --git a/Assets/Scripts/OpenTS2/NSpeex/SpeexFrame.cs.meta b/Assets/Scripts/OpenTS2/NSpeex/SpeexFrame.cs.meta new file mode 100644 index 00000000..8ff1b6fa --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/SpeexFrame.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fab57af0919cb0048b7b536f317541aa +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/NSpeex/SpeexHeader.cs b/Assets/Scripts/OpenTS2/NSpeex/SpeexHeader.cs new file mode 100644 index 00000000..1a5e5deb --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/SpeexHeader.cs @@ -0,0 +1,71 @@ +using System; +using System.Data; + +namespace NSpeex +{ + public class SpeexHeader + { + + public int SampleRate { get; set; } + /// + ///
    + ///
  • 0=NB
  • + ///
  • 1=WB
  • + ///
  • 2=UWB
  • + ///
+ ///
+ public BandMode Mode { get; set; } + + /// + /// + /// + public int Channels { get; set; } + + + public bool Vbr { get; set; } + + /// + /// + /// + public int Frames { get; set; } + + public int BitRate { get; set; } + + public SpeexHeader(int sampleRate, BandMode mode, int channels, bool vbr, int bitRate, int frames) + { + SampleRate = sampleRate; + Mode = mode; + Channels = channels; + Vbr = vbr; + this.BitRate = bitRate; + Frames = frames; + } + + /// + /// build data 80 bytes + /// + /// + public byte[] BuildData() + { + byte[] data = new byte[80]; + LittleEndian.WriteString(data, 0, "Speex ");// 0 - 7: speex_string + LittleEndian.WriteString(data, 8, "speex-1.0");// 8 - 27: speex_version + Array.Copy(new byte[11],0,data,17,11); + LittleEndian.WriteInt(data, 28, 1);// 28 - 31: speex_version_id + LittleEndian.WriteInt(data, 32, 80);// 32 - 35: header_size + LittleEndian.WriteInt(data, 36, SampleRate);// 36 - 39: rate + LittleEndian.WriteInt(data, 40, (int)Mode);//40 - 43: mode (0=NB, 1=WB, 2=UWB) + LittleEndian.WriteInt(data, 44, 4);// 44 - 47: mode_bitstream_version + LittleEndian.WriteInt(data, 48, Channels);//48 - 51: nb_channels 1,2 + LittleEndian.WriteInt(data, 52, BitRate);//// 52 - 55: bitrate + LittleEndian.WriteInt(data, 56, 160 << (int)Mode);// 56 - 59: frame_size (NB=160, WB=320, UWB=640) + LittleEndian.WriteInt(data, 60, Vbr ? 1 : 0);//60 - 63: vbr + LittleEndian.WriteInt(data, 64, Frames);//64 - 67: frames_per_packet + LittleEndian.WriteInt(data,68,0);//68 - 71: extra_headers + LittleEndian.WriteInt(data, 72, 0);//72 - 75: reserved1 + LittleEndian.WriteInt(data, 76, 0);//76 - 79: reserved2 + return data; + } + + } +} diff --git a/Assets/Scripts/OpenTS2/NSpeex/SpeexHeader.cs.meta b/Assets/Scripts/OpenTS2/NSpeex/SpeexHeader.cs.meta new file mode 100644 index 00000000..7e1d7337 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/SpeexHeader.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 33ad8d4eb71ce7340a1c0d84286d0cbd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/NSpeex/SpeexPacket.cs b/Assets/Scripts/OpenTS2/NSpeex/SpeexPacket.cs new file mode 100644 index 00000000..c7d5384e --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/SpeexPacket.cs @@ -0,0 +1,52 @@ +using System; + +namespace NSpeex +{ + public class SpeexPacket + { + public int FramePerPacket { get; set; } + + public int FrameSize { get; private set; } + + + private byte[] bytes; + + public SpeexPacket(int framePerPacket) + { + FramePerPacket = framePerPacket; + FrameSize = 0; + Size = 0; + Data = new byte[SpeexFrame.FRAME_MAX_SIZE * framePerPacket]; + } + + + public void Reset() + { + FrameSize = 0; + Size = 0; + } + + public void AddFrame(SpeexFrame frame) + { + if (FrameSize >= FramePerPacket) + { + throw new ArgumentException("out of range"); + } + FrameSize = FrameSize + 1; + Array.Copy(frame.Data,0,Data,Size,frame.Size); + Size = Size + frame.Size; + + } + + public int Size { get; private set; } + + public byte[] Data { get; private set; } + + + + + + + + } +} diff --git a/Assets/Scripts/OpenTS2/NSpeex/SpeexPacket.cs.meta b/Assets/Scripts/OpenTS2/NSpeex/SpeexPacket.cs.meta new file mode 100644 index 00000000..d8c5f38a --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/SpeexPacket.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 49c85b314eb3589448c1fec1698ce188 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/NSpeex/SplitShapeSearch.cs b/Assets/Scripts/OpenTS2/NSpeex/SplitShapeSearch.cs new file mode 100644 index 00000000..f603df2b --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/SplitShapeSearch.cs @@ -0,0 +1,401 @@ +// +// Copyright (C) 2003 Jean-Marc Valin +// Copyright (C) 1999-2003 Wimba S.A., All Rights Reserved. +// Copyright (C) 2008 Filip Navara +// Copyright (C) 2009-2010 Christoph Frschl +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// - Neither the name of the Xiph.org Foundation nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +using System.Collections.Generic; +using System.Collections; +using System; +#if FIXED_POINT +using SpeexWord16 = System.Int16; +using SpeexWord32 = System.Int32; +#else +using SpeexWord16 = System.Single; +using SpeexWord32 = System.Single; +#endif + +namespace NSpeex +{ + /// + /// Split shape codebook search + /// + internal class SplitShapeSearch : CodebookSearch + { + private const int MAX_COMPLEXITY = 10; + + private int subframesize; + private int subvect_size; + private int nb_subvect; + private int[] shape_cb; + private int shape_cb_size; + private int shape_bits; + private int have_sign; + private int[] ind; + private int[] signs; + // Varibles used by the encoder + private SpeexWord32[] E; + private SpeexWord16[] t; + private SpeexWord16[] r2; + private SpeexWord32[] e; + private SpeexWord16[][] ot, nt; + private int[,] nind, oind; + + /// + /// Constructor + /// + public SplitShapeSearch( + int subframesize_0, int subvect_size_1, + int nb_subvect_2, int[] shape_cb_3, + int shape_bits_4, int have_sign_5) + { + this.subframesize = subframesize_0; + this.subvect_size = subvect_size_1; + this.nb_subvect = nb_subvect_2; + this.shape_cb = shape_cb_3; + this.shape_bits = shape_bits_4; + this.have_sign = have_sign_5; + this.ind = new int[nb_subvect_2]; + this.signs = new int[nb_subvect_2]; + shape_cb_size = 1 << shape_bits_4; + ot = CreateJaggedArray(MAX_COMPLEXITY, subframesize_0); + nt = CreateJaggedArray(MAX_COMPLEXITY, subframesize_0); + oind = new int[MAX_COMPLEXITY, nb_subvect_2]; + nind = new int[MAX_COMPLEXITY, nb_subvect_2]; + t = new SpeexWord16[subframesize_0]; + e = new SpeexWord32[subframesize_0]; + r2 = new SpeexWord16[subframesize_0]; + E = new SpeexWord32[shape_cb_size]; + } + + private T[][] CreateJaggedArray(int dim1, int dim2) + { + T[][] a1 = new T[dim1][]; + for (int i = 0; i < dim1; i++) + { + a1[i] = new T[dim2]; + Array.Clear(a1[i], 0, dim2); + } + return a1; + } + + /// + /// Codebook Search Quantification (Split Shape). + /// + /// target vector + /// LPCs for this subframe + /// Weighted LPCs for this subframe + /// Weighted LPCs for this subframe + /// number of LPC coeffs + /// number of samples in subframe + /// excitation array. + /// position in excitation array. + /// + /// Speex bits buffer. + /// + public sealed override void Quantify( + SpeexWord16[] target, SpeexWord16[] ak, SpeexWord16[] awk1, + SpeexWord16[] awk2, int p, int nsf, SpeexWord32[] exc, int es, SpeexWord16[] r, + Bits bits, int complexity) + { + int i, j, k, m, n, q; + SpeexWord16[] resp; + SpeexWord32[] ndist, odist; + int[] best_index; + SpeexWord32[] best_dist; + int[] best_nind; + int[] best_ntarget; + + int N = complexity; + if (N > 10) + N = 10; + + resp = new SpeexWord16[shape_cb_size * subvect_size]; + + best_index = new int[N]; + best_dist = new SpeexWord32[N]; + ndist = new SpeexWord32[N]; + odist = new SpeexWord32[N]; + best_nind = new int[N]; + best_ntarget = new int[N]; + + for (i = 0; i < N; i++) + { + for (j = 0; j < nb_subvect; j++) + nind[i, j] = oind[i, j] = -1; + } + + for (j = 0; j < N; j++) + for (i = 0; i < nsf; i++) + ot[j][i] = target[i]; + + // System.arraycopy(target, 0, t, 0, nsf); + + /* Pre-compute codewords response and energy */ + for (i = 0; i < shape_cb_size; i++) + { + int res; + int shape; + + res = i * subvect_size; + shape = i * subvect_size; + + /* Compute codeword response using convolution with impulse response */ + for (j = 0; j < subvect_size; j++) + { + resp[res + j] = 0; + for (k = 0; k <= j; k++) +#if FIXED_POINT + resp[res + j] += (short)((shape_cb[shape + k] * r[j - k]) >> 13); +#else + resp[res + j] += 0.03125f * shape_cb[shape + k] * r[j - k]; +#endif + } + + /* Compute codeword energy */ + E[i] = 0; + for (j = 0; j < subvect_size; j++) + E[i] += resp[res + j] * resp[res + j]; + } + + for (j = 0; j < N; j++) + odist[j] = 0; + + /* For all subvectors */ + for (i = 0; i < nb_subvect; i++) + { + int offset = i * subvect_size; + + /* "erase" nbest list */ + for (j = 0; j < N; j++) + ndist[j] = Int32.MaxValue; + /* This is not strictly necessary, but it provides an additonal safety + to prevent crashes in case something goes wrong in the previous + steps (e.g. NaNs) */ + for (j = 0; j < N; j++) + best_nind[j] = best_ntarget[j] = 0; + + /* For all n-bests of previous subvector */ + for (j = 0; j < N; j++) + { + SpeexWord32 tener = 0; + for (m = offset; m < offset + subvect_size; m++) + tener += ot[j][m] * ot[j][m]; +#if FIXED_POINT + tener = tener >> 1; +#else + tener *= 0.5f; +#endif + + /* Find new n-best based on previous n-best j */ + if (have_sign != 0) + NSpeex.VQ.Nbest_sign( + ot[j], offset, resp, subvect_size, + shape_cb_size, E, N, best_index, best_dist); + else + NSpeex.VQ.Nbest( + ot[j], offset, resp, subvect_size, + shape_cb_size, E, N, best_index, best_dist); + + /* For all new n-bests */ + for (k = 0; k < N; k++) + { + /* Compute total distance (including previous sub-vectors */ + SpeexWord32 err = odist[j] + best_dist[k] + tener; + + /* Update n-best list */ + if (err < ndist[N - 1]) + { + for (m = 0; m < N; m++) + { + if (err < ndist[m]) + { + for (n = N - 1; n > m; n--) + { + ndist[n] = ndist[n - 1]; + best_nind[n] = best_nind[n - 1]; + best_ntarget[n] = best_ntarget[n - 1]; + } + /* n is equal to m here, so they're interchangeable */ + ndist[m] = err; + best_nind[n] = best_index[k]; + best_ntarget[n] = j; + break; + } + } + } + } + if (i == 0) + break; + } + + for (j = 0; j < N; j++) + { + /*previous target (we don't care what happened before*/ + for (m = (i + 1) * subvect_size; m < nsf; m++) + nt[j][m] = ot[best_ntarget[j]][m]; + + /* New code: update the rest of the target only if it's worth it */ + for (m = 0; m < subvect_size; m++) + { + SpeexWord16 g; + int rind; + SpeexWord16 sign = 1; + rind = best_nind[j]; + if (rind >= shape_cb_size) + { + sign = -1; + rind -= shape_cb_size; + } + + q = subvect_size - m; +#if FIXED_POINT + g = (short)(sign * shape_cb[rind * subvect_size + m]); +#else + g = sign * 0.03125f * shape_cb[rind * subvect_size + m]; +#endif + int ni; + for (n = 0, ni = offset + subvect_size; n < nsf - subvect_size * (i + 1); n++, ni++) +#if FIXED_POINT + nt[j][ni] -= (short)((g * r[n + q]) >> 13); +#else + nt[j][ni] -= (g * r[n + q]); +#endif + } + + for (q = 0; q < nb_subvect; q++) + nind[j, q] = oind[best_ntarget[j], q]; + nind[j, i] = best_nind[j]; + } + + /*update old-new data*/ + /* just swap pointers instead of a long copy */ + { + SpeexWord16[][] tmp2; + tmp2 = ot; + ot = nt; + nt = tmp2; + } + + for (j = 0; j < N; j++) + for (m = 0; m < nb_subvect; m++) + oind[j, m] = nind[j, m]; + for (j = 0; j < N; j++) + odist[j] = ndist[j]; + } + + /* save indices */ + for (i = 0; i < nb_subvect; i++) + { + ind[i] = nind[0, i]; + bits.Pack(ind[i], shape_bits + have_sign); + } + + /* Put everything back together */ + for (i = 0; i < nb_subvect; i++) + { + int rind_3; + SpeexWord16 sign_4 = 1; + rind_3 = ind[i]; + if (rind_3 >= shape_cb_size) + { + sign_4 = -1; + rind_3 -= shape_cb_size; + } + +#if FIXED_POINT + if (sign_4 == 1) + { + for (j = 0; j < subvect_size; j++) + e[subvect_size * i + j] = (int)(shape_cb[rind_3 * subvect_size + j]) >> (14 - 5); + } + else + { + for (j = 0; j < subvect_size; j++) + e[subvect_size * i + j] = -((int)(shape_cb[rind_3 * subvect_size + j]) >> (14 - 5)); + } +#else + for (j = 0; j < subvect_size; j++) + e[subvect_size * i + j] = sign_4 * 0.03125f * shape_cb[rind_3 * subvect_size + j]; +#endif + } + /* Update excitation */ + for (j = 0; j < nsf; j++) + exc[es + j] += e[j]; + + /* Update target */ + NSpeex.Filters.Syn_percep_zero(e, 0, ak, awk1, awk2, r2, nsf, p); + for (j = 0; j < nsf; j++) + target[j] -= r2[j]; + } + + /// + /// Codebook Search Unquantification (Split Shape). + /// + public sealed override void Unquantify(SpeexWord32[] exc, int es, int nsf, Bits bits) + { + int i, j; + + /* Decode codewords and gains */ + for (i = 0; i < nb_subvect; i++) + { + if (have_sign != 0) + signs[i] = bits.Unpack(1); + else + signs[i] = 0; + ind[i] = bits.Unpack(shape_bits); + } + + /* Compute decoded excitation */ + for (i = 0; i < nb_subvect; i++) + { + float s = 1.0f; + if (signs[i] != 0) + s = -1.0f; +#if FIXED_POINT + if (s == 1) + { + for (j = 0; j < subvect_size; j++) + exc[subvect_size * i + j] = (int)(shape_cb[ind[i] * subvect_size + j]) >> (14 - 5); + } + else + { + for (j = 0; j < subvect_size; j++) + exc[subvect_size * i + j] = -((int)(shape_cb[ind[i] * subvect_size + j]) << (14 - 5)); + } +#else + for (j = 0; j < subvect_size; j++) + exc[es + subvect_size * i + j] += s * 0.03125f * (float)shape_cb[ind[i] * subvect_size + j]; +#endif + } + } + } +} diff --git a/Assets/Scripts/OpenTS2/NSpeex/SplitShapeSearch.cs.meta b/Assets/Scripts/OpenTS2/NSpeex/SplitShapeSearch.cs.meta new file mode 100644 index 00000000..fddef495 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/SplitShapeSearch.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: febb7a625b364db4e8afa3f6aa38ccd4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/NSpeex/Stereo.cs b/Assets/Scripts/OpenTS2/NSpeex/Stereo.cs new file mode 100644 index 00000000..eb11cc59 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/Stereo.cs @@ -0,0 +1,246 @@ +// +// Copyright (C) 2003 Jean-Marc Valin +// Copyright (C) 1999-2003 Wimba S.A., All Rights Reserved. +// Copyright (C) 2008 Filip Navara +// Copyright (C) 2009-2010 Christoph Frschl +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// - Neither the name of the Xiph.org Foundation nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +using System.Collections.Generic; +using System.Collections; +using System; +#if FIXED_POINT +using SpeexWord16 = System.Int16; +using SpeexWord32 = System.Int32; +#else +using SpeexWord16 = System.Single; +using SpeexWord32 = System.Single; +#endif + +namespace NSpeex +{ + internal class Stereo + { + public Stereo() + { +#if FIXED_POINT + this.smooth_right = 1 << 14; + this.smooth_left = 1 << 14; + this.e_ratio = 1 << 14; + this.balance = 1 << 16; +#else + this.smooth_right = 1f; + this.smooth_left = 1f; + this.e_ratio = 0.5f; + this.balance = 1f; +#endif + } + + /// + /// Inband code number for Stereo + /// + /// + private const int SPEEX_INBAND_STEREO = 9; +#if FIXED_POINT + public static readonly SpeexWord16[] e_ratio_quant = {8192, 10332, 13009, 16384}; + public static readonly SpeexWord16[] e_ratio_quant_bounds = {9257, 11665, 14696}; + public static readonly SpeexWord16[] balance_bounds = { + 18, 23, 30, 38, 49, 63, 81, 104, + 134, 172, 221, 284, 364, 468, 600, 771, + 990, 1271, 1632, 2096, 2691, 3455, 4436, 5696, + 7314, 9392, 12059, 15484, 19882, 25529, 32766}; +#else + private static readonly float[] e_ratio_quant = { .25f, .315f, .397f, .5f }; +#endif + + /// + /// Left/right balance info + /// + private SpeexWord32 balance; + + /// + /// Ratio of energies: E(left+right)/[E(left)+E(right)] + /// + private SpeexWord32 e_ratio; + + /// + /// Smoothed left channel gain + /// + private SpeexWord32 smooth_left; + + /// + /// Smoothed right channel gain + /// + private SpeexWord32 smooth_right; + + /// + /// Transforms a stereo frame into a mono frame and stores intensity stereo + /// info in 'bits'. + /// + public static void Encode(Bits bits, SpeexWord16[] data, int frameSize) + { +#if FIXED_POINT + int i, tmp; + SpeexWord32 e_left = 0, e_right = 0, e_tot = 0; + SpeexWord32 balance, e_ratio; + SpeexWord32 largest, smallest; + int shift; + int balance_id; + + /* In band marker */ + bits.Pack(14, 5); + /* Stereo marker */ + bits.Pack(SPEEX_INBAND_STEREO, 4); + + for (i = 0; i < frameSize; i++) + { + e_left += (data[2 * i] * data[2 * i]) >> 8; + e_right += (data[2 * i + 1] * data[2 * i + 1]) >> 8; + data[i] = (SpeexWord16)((data[2 * i] >> 1) + (data[2 * i + 1] >> 1)); + e_tot += (data[i] * data[i]) >> 8; + } + + if (e_left > e_right) + { + bits.Pack(0, 1); + largest = e_left; + smallest = e_right; + } + else + { + bits.Pack(1, 1); + largest = e_right; + smallest = e_left; + } + + /* Balance quantization */ + // ??? + shift = (int)Math.Log(smallest, 2) - 15; + largest >>= shift; + smallest >>= shift; + balance = Math.Min(largest / (smallest + 1), 32767); + balance_id = VQ.Index((short)balance, balance_bounds, balance_bounds.Length); + bits.Pack((int)balance_id, 5); + + /* "coherence" quantisation */ + shift = (int)Math.Log(e_tot, 2); + e_tot >>= shift - 25; + e_left >>= shift - 10; + e_right >>= shift - 10; + e_ratio = e_tot / (e_left + e_right + 1); + + tmp = NSpeex.VQ.Index((short)e_ratio, e_ratio_quant_bounds, 4); + bits.Pack(tmp, 2); +#else + int i, tmp; + float e_left = 0, e_right = 0, e_tot = 0; + float balance_0, e_ratio_1; + for (i = 0; i < frameSize; i++) + { + e_left += data[2 * i] * data[2 * i]; + e_right += data[2 * i + 1] * data[2 * i + 1]; + data[i] = .5f * (data[2 * i] + data[2 * i + 1]); + e_tot += data[i] * data[i]; + } + balance_0 = (e_left + 1) / (e_right + 1); + e_ratio_1 = e_tot / (1 + e_left + e_right); + /* Quantization */ + bits.Pack(14, 5); + bits.Pack(SPEEX_INBAND_STEREO, 4); + balance_0 = (float)(4 * Math.Log(balance_0)); + + /* Pack balance */ + if (balance_0 > 0) + bits.Pack(0, 1); + else + bits.Pack(1, 1); + balance_0 = (float)Math.Floor(.5f + Math.Abs(balance_0)); + if (balance_0 > 30) + balance_0 = 31; + bits.Pack((int)balance_0, 5); + + /* Quantize energy ratio */ + tmp = NSpeex.VQ.Index(e_ratio_1, e_ratio_quant, 4); + bits.Pack(tmp, 2); +#endif + } + + /// + /// Transforms a mono frame into a stereo frame using intensity stereo info. + /// + /// + /// - + /// - + public void Decode(float[] data, int frameSize) + { +#if !FIXED_POINT_TODO + int i; + float e_tot = 0, e_left, e_right, e_sum; + + for (i = frameSize - 1; i >= 0; i--) + { + e_tot += data[i] * data[i]; + } + e_sum = e_tot / e_ratio; + e_left = e_sum * balance / (1 + balance); + e_right = e_sum - e_left; + e_left = (float)Math.Sqrt(e_left / (e_tot + .01f)); + e_right = (float)Math.Sqrt(e_right / (e_tot + .01f)); + + for (i = frameSize - 1; i >= 0; i--) + { + float ftmp = data[i]; + smooth_left = .98f * smooth_left + .02f * e_left; + smooth_right = .98f * smooth_right + .02f * e_right; + data[2 * i] = smooth_left * ftmp; + data[2 * i + 1] = smooth_right * ftmp; + } +#endif + } + + /// + /// Callback handler for intensity stereo info + /// + public void Init(Bits bits) + { + SpeexWord16 sign = 1; + int tmp; + if (bits.Unpack(1) != 0) + sign = -1; + tmp = bits.Unpack(5); +#if FIXED_POINT + balance = (int)Math.Exp(sign * (tmp << 9)); +#else + balance = (float)Math.Exp(sign * .25d * tmp); +#endif + tmp = bits.Unpack(2); + e_ratio = e_ratio_quant[tmp]; + } + } +} diff --git a/Assets/Scripts/OpenTS2/NSpeex/Stereo.cs.meta b/Assets/Scripts/OpenTS2/NSpeex/Stereo.cs.meta new file mode 100644 index 00000000..f6711b7f --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/Stereo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 882c60fe436c44f48a4b0196e6b563f6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/NSpeex/SubMode.cs b/Assets/Scripts/OpenTS2/NSpeex/SubMode.cs new file mode 100644 index 00000000..28e24780 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/SubMode.cs @@ -0,0 +1,170 @@ +// +// Copyright (C) 2003 Jean-Marc Valin +// Copyright (C) 1999-2003 Wimba S.A., All Rights Reserved. +// Copyright (C) 2008 Filip Navara +// Copyright (C) 2009-2010 Christoph Frschl +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// - Neither the name of the Xiph.org Foundation nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +namespace NSpeex +{ + /// + /// Speex SubMode + /// + internal class SubMode + { + private readonly int lbrPitch; + private readonly int forcedPitchGain; + private readonly int haveSubframeGain; + private readonly int doubleCodebook; + private readonly LspQuant lsqQuant; + private readonly Ltp ltp; + private readonly CodebookSearch innovation; + private readonly float lpcEnhK1; + private readonly float lpcEnhK2; + private readonly float combGain; + private readonly int bitsPerFrame; + + public SubMode( + int lbrPitch, + int forcedPitchGain, + int haveSubframeGain, + int doubleCodebook, + LspQuant lspQuant, + Ltp ltp, + CodebookSearch innovation, + float lpcEnhK1, + float lpcEnhK2, + float combGain, + int bitsPerFrame) + { + this.lbrPitch = lbrPitch; + this.forcedPitchGain = forcedPitchGain; + this.haveSubframeGain = haveSubframeGain; + this.doubleCodebook = doubleCodebook; + this.lsqQuant = lspQuant; + this.ltp = ltp; + this.innovation = innovation; + this.lpcEnhK1 = lpcEnhK1; + this.lpcEnhK2 = lpcEnhK2; + this.combGain = combGain; + this.bitsPerFrame = bitsPerFrame; + } + + /// + /// Set to -1 for "normal" modes, otherwise encode pitch using a global pitch + /// and allowing a +- lbr_pitch variation (for low not-rates) + /// + public int LbrPitch + { + get { return lbrPitch; } + } + + /// + /// Use the same (forced) pitch gain for all sub-frames + /// + public int ForcedPitchGain + { + get { return forcedPitchGain; } + } + + /// + /// Number of bits to use as sub-frame innovation gain + /// + public int HaveSubframeGain + { + get { return haveSubframeGain; } + } + + /// + /// Apply innovation quantization twice for higher quality (and higher + /// bit-rate) + /// + public int DoubleCodebook + { + get { return doubleCodebook; } + } + + /// + /// LSP quantization/unquantization function + /// + public LspQuant LsqQuant + { + get { return lsqQuant; } + } + + /// + /// Long-term predictor (pitch) un-quantizer + /// + public Ltp Ltp + { + get { return ltp; } + } + + /// + /// Codebook Search un-quantizer + /// + public CodebookSearch Innovation + { + get { return innovation; } + } + + /// + /// Enhancer constant + /// + public float LpcEnhK1 + { + get { return lpcEnhK1; } + } + + /// + /// Enhancer constant + /// + public float LpcEnhK2 + { + get { return lpcEnhK2; } + } + + /// + /// Gain of enhancer comb filter + /// + public float CombGain + { + get { return combGain; } + } + + /// + /// Number of bits per frame after encoding + /// + public int BitsPerFrame + { + get { return bitsPerFrame; } + } + } +} diff --git a/Assets/Scripts/OpenTS2/NSpeex/SubMode.cs.meta b/Assets/Scripts/OpenTS2/NSpeex/SubMode.cs.meta new file mode 100644 index 00000000..962bc236 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/SubMode.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6febef00aa1aecd4ca4907dc38d2f3e5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/NSpeex/VQ.cs b/Assets/Scripts/OpenTS2/NSpeex/VQ.cs new file mode 100644 index 00000000..99a137e1 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/VQ.cs @@ -0,0 +1,173 @@ +// +// Copyright (C) 2003 Jean-Marc Valin +// Copyright (C) 1999-2003 Wimba S.A., All Rights Reserved. +// Copyright (C) 2008 Filip Navara +// Copyright (C) 2009-2010 Christoph Frschl +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// - Neither the name of the Xiph.org Foundation nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +#if FIXED_POINT +using SpeexWord16 = System.Int16; +using SpeexWord32 = System.Int32; +#else +using SpeexWord16 = System.Single; +using SpeexWord32 = System.Single; +#endif + +namespace NSpeex +{ + /// + /// Vector Quantization. + /// + internal class VQ + { + /// + /// Finds the index of the entry in a codebook that best matches the input. + /// + /// the index of the entry in a codebook that best matches the input. + public static int Index(SpeexWord16 ins0, SpeexWord16[] codebook, int entries) + { + int i; + SpeexWord32 min_dist = 0; + int best_index = 0; + for (i = 0; i < entries; i++) + { + SpeexWord32 dist = ins0 - codebook[i]; + dist = dist * dist; + if (i == 0 || dist < min_dist) + { + min_dist = dist; + best_index = i; + } + } + return best_index; + } + + /// + /// Finds the index of the entry in a codebook that best matches the input. + /// + /// the index of the entry in a codebook that best matches the input. + public static int Index(SpeexWord16[] ins0, SpeexWord16[] codebook, int len, int entries) + { + int i, j, k = 0; + SpeexWord32 min_dist = 0; + int best_index = 0; + for (i = 0; i < entries; i++) + { + SpeexWord32 dist = 0; + for (j = 0; j < len; j++) + { + SpeexWord32 tmp = ins0[j] - codebook[k++]; + dist += tmp * tmp; + } + if (i == 0 || dist < min_dist) + { + min_dist = dist; + best_index = i; + } + } + return best_index; + } + + /// + /// Finds the indices of the n-best entries in a codebook + /// + public static void Nbest( + SpeexWord16[] ins0, int offset, SpeexWord16[] codebook, int len, int entries, + SpeexWord32[] E, int N, int[] nbest, SpeexWord32[] best_dist) + { + int i, j, k, l = 0, used = 0; + for (i = 0; i < entries; i++) + { +#if FIXED_POINT + SpeexWord32 dist = E[i] >> 1; +#else + SpeexWord32 dist = .5f * E[i]; +#endif + for (j = 0; j < len; j++) + dist -= ins0[offset + j] * codebook[l++]; + if (i < N || dist < best_dist[N - 1]) + { + for (k = N - 1; (k >= 1) && (k > used || dist < best_dist[k - 1]); k--) + { + best_dist[k] = best_dist[k - 1]; + nbest[k] = nbest[k - 1]; + } + best_dist[k] = dist; + nbest[k] = i; + used++; + } + } + } + + /// + /// Finds the indices of the n-best entries in a codebook with sign + /// + public static void Nbest_sign( + SpeexWord16[] ins0, int offset, SpeexWord16[] codebook, int len, int entries, + SpeexWord32[] E, int N, int[] nbest, SpeexWord32[] best_dist) + { + int i, j, k, l = 0, sign, used = 0; + for (i = 0; i < entries; i++) + { + SpeexWord32 dist = 0; + for (j = 0; j < len; j++) + dist -= ins0[offset + j] * codebook[l++]; + if (dist > 0) + { + sign = 1; + dist = -dist; + } + else + { + sign = 0; + } +#if FIXED_POINT + dist += E[i] >> 1; +#else + dist += .5f * E[i]; +#endif + if (i < N || dist < best_dist[N - 1]) + { + for (k = N - 1; (k >= 1) + && (k > used || dist < best_dist[k - 1]); k--) + { + best_dist[k] = best_dist[k - 1]; + nbest[k] = nbest[k - 1]; + } + best_dist[k] = dist; + nbest[k] = i; + used++; + if (sign != 0) + nbest[k] += entries; + } + } + } + } +} diff --git a/Assets/Scripts/OpenTS2/NSpeex/VQ.cs.meta b/Assets/Scripts/OpenTS2/NSpeex/VQ.cs.meta new file mode 100644 index 00000000..b74ad237 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/VQ.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ecd210672a493ba48bf0997e9f43443e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/NSpeex/Vbr.cs b/Assets/Scripts/OpenTS2/NSpeex/Vbr.cs new file mode 100644 index 00000000..564bdb0b --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/Vbr.cs @@ -0,0 +1,305 @@ +// +// Copyright (C) 2003 Jean-Marc Valin +// Copyright (C) 1999-2003 Wimba S.A., All Rights Reserved. +// Copyright (C) 2008 Filip Navara +// Copyright (C) 2009-2010 Christoph Frschl +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// - Neither the name of the Xiph.org Foundation nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +using System; + +namespace NSpeex +{ + + /// + /// This class analyses the signal to help determine what bitrate to use when the + /// Varible BitRate option has been selected. + /// + internal class Vbr + { + private const int VBR_MEMORY_SIZE = 5; + private const int MIN_ENERGY = 6000; + private const float NOISE_POW = 0.3f; + + /// + /// Narrowband threshhold table. + /// + public static readonly float[][] nb_thresh = { + new float[] { -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, + -1.0f, -1.0f, -1.0f, -1.0f }, + new float[] { 3.5f, 2.5f, 2.0f, 1.2f, 0.5f, 0.0f, -0.5f, -0.7f, + -0.8f, -0.9f, -1.0f }, + new float[] { 10.0f, 6.5f, 5.2f, 4.5f, 3.9f, 3.5f, 3.0f, 2.5f, + 2.3f, 1.8f, 1.0f }, + new float[] { 11.0f, 8.8f, 7.5f, 6.5f, 5.0f, 3.9f, 3.9f, 3.9f, + 3.5f, 3.0f, 1.0f }, + new float[] { 11.0f, 11.0f, 9.9f, 9.0f, 8.0f, 7.0f, 6.5f, 6.0f, + 5.0f, 4.0f, 2.0f }, + new float[] { 11.0f, 11.0f, 11.0f, 11.0f, 9.5f, 9.0f, 8.0f, 7.0f, + 6.5f, 5.0f, 3.0f }, + new float[] { 11.0f, 11.0f, 11.0f, 11.0f, 11.0f, 11.0f, 9.5f, 8.5f, + 8.0f, 6.5f, 4.0f }, + new float[] { 11.0f, 11.0f, 11.0f, 11.0f, 11.0f, 11.0f, 11.0f, + 11.0f, 9.8f, 7.5f, 5.5f }, + new float[] { 8.0f, 5.0f, 3.7f, 3.0f, 2.5f, 2.0f, 1.8f, 1.5f, 1.0f, + 0.0f, 0.0f } }; + + /// + /// Wideband threshhold table. + /// + public static readonly float[][] hb_thresh = { + new float[] { -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, + -1.0f, -1.0f, -1.0f, -1.0f }, + new float[] { -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, + -1.0f, -1.0f, -1.0f, -1.0f }, + new float[] { 11.0f, 11.0f, 9.5f, 8.5f, 7.5f, 6.0f, 5.0f, 3.9f, + 3.0f, 2.0f, 1.0f }, + new float[] { 11.0f, 11.0f, 11.0f, 11.0f, 11.0f, 9.5f, 8.7f, 7.8f, + 7.0f, 6.5f, 4.0f }, + new float[] { 11.0f, 11.0f, 11.0f, 11.0f, 11.0f, 11.0f, 11.0f, + 11.0f, 9.8f, 7.5f, 5.5f } }; + + /// + /// Ultra-wideband threshhold table. + /// + public static readonly float[][] uhb_thresh = { + new float[] { -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, + -1.0f, -1.0f, -1.0f, -1.0f }, + new float[] { 3.9f, 2.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, -1.0f } }; + + private float energy_alpha; + private float average_energy; + private float last_energy; + private float[] last_log_energy; + private float accum_sum; + private float last_pitch_coef; + private float soft_pitch; + private float last_quality; + private float noise_level; + private float noise_accum; + private float noise_accum_count; + private int consec_noise; + + /// + /// Constructor + /// + /// + public Vbr() + { + average_energy = 0; + last_energy = 1; + accum_sum = 0; + energy_alpha = .1f; + soft_pitch = 0; + last_pitch_coef = 0; + last_quality = 0; + + noise_accum = (float)(.05d * Math.Pow(MIN_ENERGY, NOISE_POW)); + noise_accum_count = .05f; + noise_level = noise_accum / noise_accum_count; + consec_noise = 0; + + last_log_energy = new float[VBR_MEMORY_SIZE]; + for (int i = 0; i < VBR_MEMORY_SIZE; i++) + last_log_energy[i] = (float)Math.Log(MIN_ENERGY); + } + + /// + /// This function should analyse the signal and decide how critical the + /// coding error will be perceptually. The following factors should be taken + /// into account: + ///
    + ///
  • Attacks (positive energy derivative) should be coded with more bits
  • + ///
  • Stationary voiced segments should receive more bits
  • + ///
  • Segments with (very) low absolute energy should receive less bits + /// (maybe only shaped noise?)
  • + ///
  • DTX for near-zero energy?
  • + ///
  • Stationary fricative segments should have less bits
  • + ///
  • Temporal masking: when energy slope is decreasing, decrease the + /// bit-rate
  • + ///
  • Decrease bit-rate for males (low pitch)?
  • + ///
  • (wideband only) less bits in the high-band when signal is very + /// non-stationary (harder to notice high-frequency noise)???
  • + ///
+ ///
+ /// + /// + /// + /// + /// + /// quality + public float Analysis(float[] sig, int len, int pitch, + float pitch_coef) + { + int i; + float ener = 0, ener1 = 0, ener2 = 0; + float qual = 7; + int va; + float log_energy; + float non_st = 0; + float voicing; + float pow_ener; + + for (i = 0; i < len >> 1; i++) + ener1 += sig[i] * sig[i]; + for (i = len >> 1; i < len; i++) + ener2 += sig[i] * sig[i]; + ener = ener1 + ener2; + + log_energy = (float)Math.Log(ener + MIN_ENERGY); + for (i = 0; i < VBR_MEMORY_SIZE; i++) + non_st += (log_energy - last_log_energy[i]) + * (log_energy - last_log_energy[i]); + non_st = non_st / (30 * VBR_MEMORY_SIZE); + if (non_st > 1) + non_st = 1; + + voicing = 3 * (pitch_coef - .4f) * Math.Abs(pitch_coef - .4f); + average_energy = (1 - energy_alpha) * average_energy + energy_alpha + * ener; + noise_level = noise_accum / noise_accum_count; + pow_ener = (float)Math.Pow(ener, NOISE_POW); + if (noise_accum_count < .06f && ener > MIN_ENERGY) + noise_accum = .05f * pow_ener; + + if ((voicing < .3f && non_st < .2f && pow_ener < 1.2f * noise_level) + || (voicing < .3f && non_st < .05f && pow_ener < 1.5f * noise_level) + || (voicing < .4f && non_st < .05f && pow_ener < 1.2f * noise_level) + || (voicing < 0 && non_st < .05f)) + { + float tmp; + va = 0; + consec_noise++; + if (pow_ener > 3 * noise_level) + tmp = 3 * noise_level; + else + tmp = pow_ener; + if (consec_noise >= 4) + { + noise_accum = .95f * noise_accum + .05f * tmp; + noise_accum_count = .95f * noise_accum_count + .05f; + } + } + else + { + va = 1; + consec_noise = 0; + } + + if (pow_ener < noise_level && ener > MIN_ENERGY) + { + noise_accum = .95f * noise_accum + .05f * pow_ener; + noise_accum_count = .95f * noise_accum_count + .05f; + } + + /* Checking for very low absolute energy */ + if (ener < 30000) + { + qual -= .7f; + if (ener < 10000) + qual -= .7f; + if (ener < 3000) + qual -= .7f; + } + else + { + float short_diff, long_diff; + short_diff = (float)Math.Log((ener + 1) + / (1 + last_energy)); + long_diff = (float)Math.Log((ener + 1) + / (1 + average_energy)); + /* fprintf (stderr, "%f %f\n", short_diff, long_diff); */ + + if (long_diff < -5) + long_diff = -5; + if (long_diff > 2) + long_diff = 2; + + if (long_diff > 0) + qual += .6f * long_diff; + if (long_diff < 0) + qual += .5f * long_diff; + if (short_diff > 0) + { + if (short_diff > 5) + short_diff = 5; + qual += .5f * short_diff; + } + /* Checking for energy increases */ + if (ener2 > 1.6f * ener1) + qual += .5f; + } + last_energy = ener; + soft_pitch = .6f * soft_pitch + .4f * pitch_coef; + qual += (float)(2.2f * ((pitch_coef - .4d) + (soft_pitch - .4d))); + + if (qual < last_quality) + qual = .5f * qual + .5f * last_quality; + if (qual < 4) + qual = 4; + if (qual > 10) + qual = 10; + + /* + * if (consec_noise>=2) qual-=1.3f; if (consec_noise>=5) qual-=1.3f; if + * (consec_noise>=12) qual-=1.3f; + */ + if (consec_noise >= 3) + qual = 4; + + if (consec_noise != 0) + qual -= (float)(1.0d * (Math.Log(3.0d + consec_noise) - Math.Log(3))); + if (qual < 0) + qual = 0; + + if (ener < 60000) + { + if (consec_noise > 2) + qual -= (float)(0.5d * (Math.Log(3.0d + consec_noise) - Math.Log(3))); + if (ener < 10000 && consec_noise > 2) + qual -= (float)(0.5d * (Math.Log(3.0d + consec_noise) - Math.Log(3))); + if (qual < 0) + qual = 0; + qual += (float)(.3d * Math.Log(ener / 60000.0d)); + } + if (qual < -1) + qual = -1; + + last_pitch_coef = pitch_coef; + last_quality = qual; + + for (i = VBR_MEMORY_SIZE - 1; i > 0; i--) + last_log_energy[i] = last_log_energy[i - 1]; + last_log_energy[0] = log_energy; + + return qual; + } + } +} diff --git a/Assets/Scripts/OpenTS2/NSpeex/Vbr.cs.meta b/Assets/Scripts/OpenTS2/NSpeex/Vbr.cs.meta new file mode 100644 index 00000000..936dfdb2 --- /dev/null +++ b/Assets/Scripts/OpenTS2/NSpeex/Vbr.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d4a93dff3e310564db51ab9ef26591f4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/ScriptsAssembly.asmdef b/Assets/Scripts/OpenTS2/OpenTS2.asmdef similarity index 92% rename from Assets/Scripts/OpenTS2/ScriptsAssembly.asmdef rename to Assets/Scripts/OpenTS2/OpenTS2.asmdef index 108fcf4e..83c03a0c 100644 --- a/Assets/Scripts/OpenTS2/ScriptsAssembly.asmdef +++ b/Assets/Scripts/OpenTS2/OpenTS2.asmdef @@ -1,5 +1,5 @@ { - "name": "ScriptsAssembly", + "name": "OpenTS2", "rootNamespace": "", "references": [ "GUID:7f7d1af65c2641843945d409d28f2e20" diff --git a/Assets/Scripts/OpenTS2/ScriptsAssembly.asmdef.meta b/Assets/Scripts/OpenTS2/OpenTS2.asmdef.meta similarity index 100% rename from Assets/Scripts/OpenTS2/ScriptsAssembly.asmdef.meta rename to Assets/Scripts/OpenTS2/OpenTS2.asmdef.meta diff --git a/Assets/Scripts/OpenTS2/Rendering/Batching.cs b/Assets/Scripts/OpenTS2/Rendering/Batching.cs index 55ea7ebc..a23d5a7f 100644 --- a/Assets/Scripts/OpenTS2/Rendering/Batching.cs +++ b/Assets/Scripts/OpenTS2/Rendering/Batching.cs @@ -69,9 +69,8 @@ public void RestoreVisibility() } // Might not play nice with some hardware, maybe adjust conditionally. - [ConsoleProperty("ots2_batchingVertexLimit")] public static int DefaultVertexLimit = 10000000; - static Dictionary s_shadersCantBeBatched = new Dictionary(); + static Dictionary ShadersCantBeBatched = new Dictionary(); /// /// Prevents specific shaders from getting batched. @@ -93,12 +92,12 @@ public static void MarkShadersNoBatching(params string[] shaders) public static void MarkShadersNoBatching(params Shader[] shaders) { foreach(var shader in shaders) - s_shadersCantBeBatched[shader] = true; + ShadersCantBeBatched[shader] = true; } static bool CanBatchShader(Shader shader) { - if (!s_shadersCantBeBatched.ContainsKey(shader)) + if (!ShadersCantBeBatched.ContainsKey(shader)) return true; return false; } diff --git a/Assets/Scripts/OpenTS2/Rendering/CameraReflection.cs b/Assets/Scripts/OpenTS2/Rendering/CameraReflection.cs index 8b5c094d..cc002bc3 100644 --- a/Assets/Scripts/OpenTS2/Rendering/CameraReflection.cs +++ b/Assets/Scripts/OpenTS2/Rendering/CameraReflection.cs @@ -1,3 +1,5 @@ +using OpenTS2.Content; +using OpenTS2.Engine; using System.Collections; using System.Collections.Generic; using UnityEngine; @@ -5,6 +7,8 @@ [RequireComponent(typeof(Camera))] public class CameraReflection : MonoBehaviour { + [GameProperty(false)] + public static float ReflectionResolutionFactor = 0.5f; public Color ReflectionSkyColor; public static CameraReflection Instance; public Camera reflectionCamera; @@ -15,11 +19,13 @@ public class CameraReflection : MonoBehaviour private void Awake() { Instance = this; - ReflectionTexture = new RenderTexture(Screen.width, Screen.height, 24); + ReflectionTexture = new RenderTexture((int)(Screen.width * ReflectionResolutionFactor), (int)(Screen.height * ReflectionResolutionFactor), 24); var reflectionCameraGameObject = new GameObject("Reflection Camera"); reflectionCamera = reflectionCameraGameObject.AddComponent(); _camera = GetComponent(); reflectionCamera.CopyFrom(_camera); + reflectionCamera.allowMSAA = false; + reflectionCamera.cullingMask = 1 << Layers.Default | 1 << Layers.Terrain; reflectionCamera.targetTexture = ReflectionTexture; reflectionCamera.enabled = false; reflectionCamera.backgroundColor = ReflectionSkyColor; diff --git a/Assets/Scripts/OpenTS2/Rendering/LightmapManager.cs b/Assets/Scripts/OpenTS2/Rendering/LightmapManager.cs index 8817f076..b3abd04d 100644 --- a/Assets/Scripts/OpenTS2/Rendering/LightmapManager.cs +++ b/Assets/Scripts/OpenTS2/Rendering/LightmapManager.cs @@ -13,20 +13,18 @@ namespace OpenTS2.Rendering public static class LightmapManager { public const float HeightDivision = 1000f; - public static RenderTexture ShadowMap => s_shadowMap; - public static RenderTexture ShoreMap => s_shoreMap; - private static RenderTexture s_heightMap; - private static Shader s_heightMapShader = Shader.Find("OpenTS2/TerrainHeightmap"); - private static Material s_heightMapMaterial = new Material(s_heightMapShader); - private static RenderTexture s_shadowMap; - private static Shader s_shadowMapShader = Shader.Find("OpenTS2/HeightMapShadows"); - private static Material s_shadowMapMaterial = new Material(s_shadowMapShader); - private static RenderTexture s_shoreMap; - private static Shader s_shoreMapShader = Shader.Find("OpenTS2/ShoreMask"); - private static Material s_shoreMapMaterial = new Material(s_shoreMapShader); - private static int s_shadowMapResolution = 256; - private static int s_heightMapResolution = 256; - private static int s_shoreResolution = 64; + public static RenderTexture ShadowMap { get; private set; } + public static RenderTexture ShoreMap { get; private set; } + private static RenderTexture HeightMap; + private static Shader HeightMapShader = Shader.Find("OpenTS2/TerrainHeightmap"); + private static Material HeightMapMaterial = new Material(HeightMapShader); + private static Shader ShadowMapShader = Shader.Find("OpenTS2/HeightMapShadows"); + private static Material ShadowMapMaterial = new Material(ShadowMapShader); + private static Shader ShoreMapShader = Shader.Find("OpenTS2/ShoreMask"); + private static Material ShoreMapMaterial = new Material(ShoreMapShader); + private static int ShadowMapResolution = 256; + private static int HeightMapResolution = 256; + private static int ShoreResolution = 64; /// /// Renders lightmapping for the current neighborhood. @@ -37,32 +35,32 @@ public static void RenderShadowMap() var meshFilter = terrain.GetComponent(); var sun = terrain.Sun; var mesh = meshFilter.sharedMesh; - var neighborhood = NeighborhoodManager.CurrentNeighborhood; + var neighborhood = NeighborhoodManager.Instance.CurrentNeighborhood; - if (s_heightMap == null) - s_heightMap = new RenderTexture(s_heightMapResolution, s_heightMapResolution, 16, RenderTextureFormat.R16); - RenderTexture.active = s_heightMap; - s_heightMapMaterial.SetPass(0); - s_heightMapMaterial.SetFloat("_HeightDivision", HeightDivision); - s_heightMapMaterial.SetFloat("_Width", neighborhood.Terrain.Width); - s_heightMapMaterial.SetFloat("_Height", neighborhood.Terrain.Height); + if (HeightMap == null) + HeightMap = new RenderTexture(HeightMapResolution, HeightMapResolution, 16, RenderTextureFormat.R16); + RenderTexture.active = HeightMap; + HeightMapMaterial.SetPass(0); + HeightMapMaterial.SetFloat("_HeightDivision", HeightDivision); + HeightMapMaterial.SetFloat("_Width", neighborhood.Terrain.Width); + HeightMapMaterial.SetFloat("_Height", neighborhood.Terrain.Height); Graphics.DrawMeshNow(mesh, Vector3.zero, Quaternion.identity); RenderTexture.active = null; - if (s_shadowMap == null) - s_shadowMap = new RenderTexture(s_shadowMapResolution, s_shadowMapResolution, 16, RenderTextureFormat.R16); - RenderTexture.active = s_shadowMap; - s_shadowMapMaterial.mainTexture = s_heightMap; - s_shadowMapMaterial.SetVector("_LightVector", sun.forward); - Graphics.Blit(s_heightMap, s_shadowMapMaterial); + if (ShadowMap == null) + ShadowMap = new RenderTexture(ShadowMapResolution, ShadowMapResolution, 16, RenderTextureFormat.R16); + RenderTexture.active = ShadowMap; + ShadowMapMaterial.mainTexture = HeightMap; + ShadowMapMaterial.SetVector("_LightVector", sun.forward); + Graphics.Blit(HeightMap, ShadowMapMaterial); RenderTexture.active = null; - if (s_shoreMap == null) - s_shoreMap = new RenderTexture(s_shoreResolution, s_shoreResolution, 16, RenderTextureFormat.R16); - RenderTexture.active = s_shoreMap; - s_shoreMapMaterial.mainTexture = s_heightMap; - s_shoreMapMaterial.SetFloat("_SeaLevel", neighborhood.Terrain.SeaLevel / HeightDivision); - Graphics.Blit(s_heightMap, s_shoreMapMaterial); + if (ShoreMap == null) + ShoreMap = new RenderTexture(ShoreResolution, ShoreResolution, 16, RenderTextureFormat.R16); + RenderTexture.active = ShoreMap; + ShoreMapMaterial.mainTexture = HeightMap; + ShoreMapMaterial.SetFloat("_SeaLevel", neighborhood.Terrain.SeaLevel / HeightDivision); + Graphics.Blit(HeightMap, ShoreMapMaterial); RenderTexture.active = null; } } diff --git a/Assets/Scripts/OpenTS2/Rendering/MaterialManager.cs b/Assets/Scripts/OpenTS2/Rendering/MaterialManager.cs index 2cb2806d..ab5bd43a 100644 --- a/Assets/Scripts/OpenTS2/Rendering/MaterialManager.cs +++ b/Assets/Scripts/OpenTS2/Rendering/MaterialManager.cs @@ -14,7 +14,7 @@ namespace OpenTS2.Rendering /// public static class MaterialManager { - private static Dictionary s_materials = new Dictionary(); + private static Dictionary Materials = new Dictionary(); public static void Initialize() { RegisterMaterial(); @@ -47,7 +47,7 @@ public static void Initialize() public static Material Parse(ScenegraphMaterialDefinitionAsset definition, string forceType) { - if (!s_materials.TryGetValue(forceType ?? definition.MaterialDefinition.Type, out AbstractMaterial material)) + if (!Materials.TryGetValue(forceType ?? definition.MaterialDefinition.Type, out AbstractMaterial material)) throw new KeyNotFoundException($"Can't find material type {definition.MaterialDefinition.Type} for {definition.MaterialDefinition.MaterialName}"); return material.Parse(definition); } @@ -55,7 +55,7 @@ public static Material Parse(ScenegraphMaterialDefinitionAsset definition, strin public static void RegisterMaterial() where T : AbstractMaterial { var mat = Activator.CreateInstance(typeof(T)) as AbstractMaterial; - s_materials[mat.Name] = mat; + Materials[mat.Name] = mat; } } } diff --git a/Assets/Scripts/OpenTS2/Rendering/MaterialUtils.cs b/Assets/Scripts/OpenTS2/Rendering/MaterialUtils.cs index a3cd2214..ebfc4eaf 100644 --- a/Assets/Scripts/OpenTS2/Rendering/MaterialUtils.cs +++ b/Assets/Scripts/OpenTS2/Rendering/MaterialUtils.cs @@ -10,23 +10,23 @@ namespace OpenTS2.Rendering { public static class MaterialUtils { - private static int s_shadowMap = Shader.PropertyToID("_ShadowMap"); - private static int s_terrainWidth = Shader.PropertyToID("_TerrainWidth"); - private static int s_terrainHeight = Shader.PropertyToID("_TerrainHeight"); - private static int s_seaLevel = Shader.PropertyToID("_SeaLevel"); + private static int ShadowMap = Shader.PropertyToID("_ShadowMap"); + private static int TerrainWidth = Shader.PropertyToID("_TerrainWidth"); + private static int TerrainHeight = Shader.PropertyToID("_TerrainHeight"); + private static int SeaLevel = Shader.PropertyToID("_SeaLevel"); /// /// Send neighborhood lightmap textures and information to a shader. /// public static void SetNeighborhoodParameters(Material material) { - var ngbh = NeighborhoodManager.CurrentNeighborhood; + var ngbh = NeighborhoodManager.Instance.CurrentNeighborhood; if (ngbh != null) { - material.SetTexture(s_shadowMap, LightmapManager.ShadowMap); - material.SetFloat(s_terrainWidth, ngbh.Terrain.Width); - material.SetFloat(s_terrainHeight, ngbh.Terrain.Height); - material.SetFloat(s_seaLevel, ngbh.Terrain.SeaLevel); + material.SetTexture(ShadowMap, LightmapManager.ShadowMap); + material.SetFloat(TerrainWidth, ngbh.Terrain.Width); + material.SetFloat(TerrainHeight, ngbh.Terrain.Height); + material.SetFloat(SeaLevel, ngbh.Terrain.SeaLevel); } } } diff --git a/Assets/Scripts/OpenTS2/Rendering/Materials/ImposterDualPackedSliceMaterial.cs b/Assets/Scripts/OpenTS2/Rendering/Materials/ImposterDualPackedSliceMaterial.cs index 86f63f5c..af5a41c2 100644 --- a/Assets/Scripts/OpenTS2/Rendering/Materials/ImposterDualPackedSliceMaterial.cs +++ b/Assets/Scripts/OpenTS2/Rendering/Materials/ImposterDualPackedSliceMaterial.cs @@ -23,11 +23,11 @@ public override Material Parse(ScenegraphMaterialDefinitionAsset definition) var shader = Shader.Find("OpenTS2/LotImposterCutOut"); var material = new Material(shader); - var texture = ContentProvider.Get().GetAsset( + var texture = ContentManager.Instance.GetAsset( new ResourceKey(textureName, definition.GlobalTGI.GroupID, TypeIDs.SCENEGRAPH_TXTR) ); definition.Textures.Add(texture); - material.mainTexture = texture.GetSelectedImageAsUnityTexture(ContentProvider.Get()); + material.mainTexture = texture.GetSelectedImageAsUnityTexture(); material.mainTexture.filterMode = FilterMode.Point; material.SetFloat(AlphaCutOff, 0.5f); return material; diff --git a/Assets/Scripts/OpenTS2/Rendering/Materials/ImposterRoofMaterial.cs b/Assets/Scripts/OpenTS2/Rendering/Materials/ImposterRoofMaterial.cs index b67f5dbc..df9f2aa9 100644 --- a/Assets/Scripts/OpenTS2/Rendering/Materials/ImposterRoofMaterial.cs +++ b/Assets/Scripts/OpenTS2/Rendering/Materials/ImposterRoofMaterial.cs @@ -23,11 +23,11 @@ public override Material Parse(ScenegraphMaterialDefinitionAsset definition) var shader = Shader.Find("OpenTS2/LotImposterRoof"); var material = new Material(shader); - var texture = ContentProvider.Get().GetAsset( + var texture = ContentManager.Instance.GetAsset( new ResourceKey(textureName, definition.GlobalTGI.GroupID, TypeIDs.SCENEGRAPH_TXTR) ); definition.Textures.Add(texture); - material.mainTexture = texture.GetSelectedImageAsUnityTexture(ContentProvider.Get()); + material.mainTexture = texture.GetSelectedImageAsUnityTexture(); material.SetFloat(Size, Lot.MaxLotSize); return material; } diff --git a/Assets/Scripts/OpenTS2/Rendering/Materials/ImposterTerrainMaterial.cs b/Assets/Scripts/OpenTS2/Rendering/Materials/ImposterTerrainMaterial.cs index 85c1cdb9..f056efa9 100644 --- a/Assets/Scripts/OpenTS2/Rendering/Materials/ImposterTerrainMaterial.cs +++ b/Assets/Scripts/OpenTS2/Rendering/Materials/ImposterTerrainMaterial.cs @@ -21,11 +21,11 @@ public override Material Parse(ScenegraphMaterialDefinitionAsset definition) var shader = Shader.Find("OpenTS2/LotImposterBlend"); var material = new Material(shader); - var texture = ContentProvider.Get().GetAsset( + var texture = ContentManager.Instance.GetAsset( new ResourceKey(textureName, definition.GlobalTGI.GroupID, TypeIDs.SCENEGRAPH_TXTR) ); definition.Textures.Add(texture); - material.mainTexture = texture.GetSelectedImageAsUnityTexture(ContentProvider.Get()); + material.mainTexture = texture.GetSelectedImageAsUnityTexture(); return material; } } diff --git a/Assets/Scripts/OpenTS2/Rendering/Materials/ImposterWallMaterial.cs b/Assets/Scripts/OpenTS2/Rendering/Materials/ImposterWallMaterial.cs index a55ced60..f6fb0bfa 100644 --- a/Assets/Scripts/OpenTS2/Rendering/Materials/ImposterWallMaterial.cs +++ b/Assets/Scripts/OpenTS2/Rendering/Materials/ImposterWallMaterial.cs @@ -23,11 +23,11 @@ public override Material Parse(ScenegraphMaterialDefinitionAsset definition) var shader = Shader.Find("OpenTS2/LotImposterCutOut"); var material = new Material(shader); - var texture = ContentProvider.Get().GetAsset( + var texture = ContentManager.Instance.GetAsset( new ResourceKey(textureName, definition.GlobalTGI.GroupID, TypeIDs.SCENEGRAPH_TXTR) ); definition.Textures.Add(texture); - material.mainTexture = texture.GetSelectedImageAsUnityTexture(ContentProvider.Get()); + material.mainTexture = texture.GetSelectedImageAsUnityTexture(); material.mainTexture.filterMode = FilterMode.Point; material.SetFloat(AlphaCutOff, 0.5f); return material; diff --git a/Assets/Scripts/OpenTS2/Rendering/Materials/StandardMaterial.cs b/Assets/Scripts/OpenTS2/Rendering/Materials/StandardMaterial.cs index 28cae417..634e2962 100644 --- a/Assets/Scripts/OpenTS2/Rendering/Materials/StandardMaterial.cs +++ b/Assets/Scripts/OpenTS2/Rendering/Materials/StandardMaterial.cs @@ -58,7 +58,7 @@ public override Material Parse(ScenegraphMaterialDefinitionAsset definition) bumpMapEnabled = true; break; case "stdMatNormalMapTextureName": - bumpMapTexture = ContentProvider.Get().GetAsset( + bumpMapTexture = ContentManager.Instance.GetAsset( new ResourceKey(property.Value + "_txtr", definition.GlobalTGI.GroupID, TypeIDs.SCENEGRAPH_TXTR) ); if (bumpMapTexture == null) @@ -73,7 +73,7 @@ public override Material Parse(ScenegraphMaterialDefinitionAsset definition) break; case "stdMatBaseTextureName": var textureName = property.Value; - var texture = ContentProvider.Get().GetAsset( + var texture = ContentManager.Instance.GetAsset( new ResourceKey(textureName + "_txtr", definition.GlobalTGI.GroupID, TypeIDs.SCENEGRAPH_TXTR) ); if (texture == null) @@ -82,7 +82,7 @@ public override Material Parse(ScenegraphMaterialDefinitionAsset definition) break; } definition.Textures.Add(texture); - material.mainTexture = texture.GetSelectedImageAsUnityTexture(ContentProvider.Get()); + material.mainTexture = texture.GetSelectedImageAsUnityTexture(); break; case "stdMatAlphaMultiplier": alphaMul = float.Parse(property.Value); @@ -102,13 +102,13 @@ public override Material Parse(ScenegraphMaterialDefinitionAsset definition) if (bumpMapEnabled && bumpMapTexture != null) { definition.Textures.Add(bumpMapTexture); - material.SetTexture(BumpMap, bumpMapTexture.GetSelectedImageAsUnityTexture(ContentProvider.Get())); + material.SetTexture(BumpMap, bumpMapTexture.GetSelectedImageAsUnityTexture()); } - var neighborhood = NeighborhoodManager.CurrentNeighborhood; + var neighborhood = NeighborhoodManager.Instance.CurrentNeighborhood; if (neighborhood != null) { - material.SetFloat(SeaLevel, NeighborhoodManager.CurrentNeighborhood.Terrain.SeaLevel); + material.SetFloat(SeaLevel, NeighborhoodManager.Instance.CurrentNeighborhood.Terrain.SeaLevel); } return material; diff --git a/Assets/Scripts/OpenTS2/Scenes/Lot/Extensions.meta b/Assets/Scripts/OpenTS2/Scenes/Lot/Extensions.meta new file mode 100644 index 00000000..faec23cf --- /dev/null +++ b/Assets/Scripts/OpenTS2/Scenes/Lot/Extensions.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a72c7287d7d00824197bc42606cacaca +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Scenes/Lot/Extensions/LotArchitectureBuildModeExtensions.cs b/Assets/Scripts/OpenTS2/Scenes/Lot/Extensions/LotArchitectureBuildModeExtensions.cs new file mode 100644 index 00000000..ad48ac49 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Scenes/Lot/Extensions/LotArchitectureBuildModeExtensions.cs @@ -0,0 +1,201 @@ +using Codice.CM.Triggers; +using Codice.Utils; +using log4net.Core; +using OpenTS2.Content.DBPF; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace OpenTS2.Scenes.Lot.Extensions +{ + //JDrocks450 'Bloaty' 12/9/23 -- Contains all build mode functions with respect to LotArchitecture instances in one unit + + /// + /// Extensions for manipulating instances for build mode operations + /// + internal static class LotArchitectureBuildModeExtensions + { + /// + /// Creates a wall. + /// This function will ensure the following: + /// The Wall is split into 1 unit long segments + /// The Wall has the wallpaper you provide added to each segment created. + /// The Wall is a straight line, diagonally, horizontally or vertically aligned + /// The Wall is of the type provided. + /// The Wall is added to the instance this is called on + /// + /// + /// + /// The point the wall originates + /// The point the wall is destined to + /// Which floor the wall is on + /// The type of wall you wish to create + /// The Pattern1 of the wall + /// The Pattern2 of the wall + /// upon total failure; no walls placed. + /// if some walls were placed. if all wall segments placed. + public static int[]? CreateWall(this LotArchitecture Architecture, Vector2 From, + Vector2 To, int Floor, WallType Type = WallType.Normal, ushort PatternFront = ushort.MaxValue, ushort PatternBack = ushort.MaxValue) + { + //get the wall's direction vector + var dirVector = To - From; + dirVector.Normalize(); + + bool diagonal = false; + + if (Math.Abs(dirVector.x) == Math.Abs(dirVector.y)) + { + dirVector = new Vector2(dirVector.x < 0 ? -1 : 1, dirVector.y < 0 ? -1 : 1); + diagonal = true; + } + if ((Math.Abs(dirVector.x) != 1 || dirVector.y != 0) && (Math.Abs(dirVector.y) != 1 || dirVector.x != 0) && + (Math.Abs(dirVector.x) != 1 || Math.Abs(dirVector.y) != 1)) // valid directions for a wall + return null; + + //subdivide the wall into 1 unit lengths (otherwise wall paints will appear stretchy) + var wallLength = (double)Math.Abs(Vector2.Distance(From, To)); + if (diagonal) wallLength *= 0.7; + + int successfulWallSegments = 0, totalSegments = (int)Math.Round(wallLength); + int[] createdWallIDs = new int[totalSegments]; + + for (int segment = 0; segment < (wallLength); segment++) + { + var fooFrom = From + (dirVector * segment); + var fooTo = From + (dirVector * (segment + 1)); + //Add wall to wallgraph + if (!Architecture.WallGraphAll.PushWall(fooFrom, fooTo, Floor, out int LayerID)) continue; + if (createdWallIDs.Length <= segment) + Array.Resize(ref createdWallIDs, segment + 1); + createdWallIDs[segment] = LayerID; + //Add wall layer data + Architecture.WallLayer.Walls.Add(LayerID, new WallLayerEntry() + { + Id = LayerID, + Pattern1 = PatternFront, + Pattern2 = PatternBack, + WallType = Type + }); + successfulWallSegments++; + } + if (successfulWallSegments <= 0) return null; // total failure + return createdWallIDs; // somewhat / complete success code + } + /// + /// Deletes wall segments between the two points provided on the given floor + /// + /// + /// + /// + /// + public static bool? DeleteWall(this LotArchitecture Architecture, Vector2 From, Vector2 To, int Floor) + { + //get the wall's direction vector + var dirVector = To - From; + dirVector.Normalize(); + + bool diagonal = false; + + if (Math.Abs(dirVector.x) == Math.Abs(dirVector.y)) + { + dirVector = new Vector2(dirVector.x < 0 ? -1 : 1, dirVector.y < 0 ? -1 : 1); + diagonal = true; + } + if ((Math.Abs(dirVector.x) != 1 || dirVector.y != 0) && (Math.Abs(dirVector.y) != 1 || dirVector.x != 0) && + (Math.Abs(dirVector.x) != 1 || Math.Abs(dirVector.y) != 1)) // valid directions for a wall + return false; + + //subdivide the wall into 1 unit lengths (otherwise wall paints will appear stretchy) + var wallLength = (double)Math.Abs(Vector2.Distance(From, To)); + if (diagonal) wallLength *= 0.7; + + int successfulWallSegments = 0, totalSegments = (int)wallLength; + for (int segment = 0; segment < (wallLength); segment++) + { + var fooFrom = From + (dirVector * segment); + var fooTo = From + (dirVector * (segment + 1)); + //Remove wall from wallgraph + if (!Architecture.WallGraphAll.RemoveWall(fooFrom, fooTo, Floor, out int LayerID)) continue; + //Remove wall layer data + Architecture.WallLayer.Walls.Remove(LayerID); + successfulWallSegments++; + } + if (successfulWallSegments <= 0) return null; // total failure + return successfulWallSegments < totalSegments ? false : true; // somewhat / complete success code + } + public static void DeleteAllWalls(this LotArchitecture Architecture, params int[] WallLayerIDs) + { + if (WallLayerIDs.Length <= 0) return; + foreach(var ID in WallLayerIDs) + { + //Remove wall from wallgraph + if (Architecture.WallGraphAll.RemoveWalls(WallLayerIDs) == 0) continue; + //Remove wall layer data + foreach(var id in WallLayerIDs) + Architecture.WallLayer.Walls.Remove(id); + } + } + /// + /// Checks to see if the given pattern name is referenced; if it isn't, will reference it in the + /// and returns the PatternID of the (potentially newly) referenced pattern + /// + /// + /// + /// + /// + /// true if the pattern was already referenced + /// + public static bool EnsurePatternReferenced(this LotArchitecture arch, string PatternName, + LotArchitecture.ArchitectureGameObjectTypes Scope, out ushort PatternID, out bool Existed) + { + Existed = false; + PatternID = 0; + + Dictionary Map = Scope switch + { + LotArchitecture.ArchitectureGameObjectTypes.wall => arch.WallMap.Map, + LotArchitecture.ArchitectureGameObjectTypes.floor => arch.FloorMap.Map, + _ => null + }; + + if (Map == null) return false; + if (Map.Count == 0) + goto create; + var hits = Map.Where(x => x.Value.Value == PatternName); + if (!hits.Any()) + goto create; + Existed = true; + PatternID = hits.FirstOrDefault().Key; + return true; + + //lord forgive me for using goto + create: + PatternID = (ushort)(Map.Count + 1); + if (Map.Any()) + PatternID = Math.Max(PatternID, (ushort)(Map.Keys.Max() + 1)); + Map.Add(PatternID, new StringMapEntry() + { + Id = PatternID, + Value = PatternName, + Unknown = 0 + }); + return true; + } + + public static float PollElevation(this LotArchitecture architecture, Vector2Int Position, int Floor = 0) + { + Floor = -architecture.BaseFloor + Floor; + + float[] dataSet = architecture.Elevation.Data[Floor]; + + var mPos = Position; + int index = (mPos.x * architecture.Elevation.Height) + mPos.y; + + return dataSet[index]; + } + } +} diff --git a/Assets/Scripts/OpenTS2/Scenes/Lot/Extensions/LotArchitectureBuildModeExtensions.cs.meta b/Assets/Scripts/OpenTS2/Scenes/Lot/Extensions/LotArchitectureBuildModeExtensions.cs.meta new file mode 100644 index 00000000..fb58a6c2 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Scenes/Lot/Extensions/LotArchitectureBuildModeExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 118886c7f98c90e44b3d7c13cbab0440 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Scenes/Lot/FenceCollection.cs b/Assets/Scripts/OpenTS2/Scenes/Lot/FenceCollection.cs index 69f4db6e..d69c3523 100644 --- a/Assets/Scripts/OpenTS2/Scenes/Lot/FenceCollection.cs +++ b/Assets/Scripts/OpenTS2/Scenes/Lot/FenceCollection.cs @@ -24,9 +24,9 @@ public class FenceCollection private bool _isVisible = true; - public FenceCollection(ContentProvider contentProvider, GameObject parent, uint guid) + public FenceCollection(ContentManager contentManager, GameObject parent, uint guid) { - var catalog = CatalogManager.Get(); + var catalog = CatalogManager.Instance; _asset = catalog.GetFenceById(guid); @@ -38,15 +38,15 @@ public FenceCollection(ContentProvider contentProvider, GameObject parent, uint _hasDiag = _asset.DiagRail != null; _parent = parent; - _railCres = contentProvider.GetAsset( + _railCres = contentManager.GetAsset( new ResourceKey(_asset.Rail + "_cres", GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_CRES)); - _diagRailCres = _hasDiag ? contentProvider.GetAsset( + _diagRailCres = _hasDiag ? contentManager.GetAsset( new ResourceKey(_asset.DiagRail + "_cres", GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_CRES)) : null; - _postCres = contentProvider.GetAsset( + _postCres = contentManager.GetAsset( new ResourceKey(_asset.Post + "_cres", GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_CRES)); diff --git a/Assets/Scripts/OpenTS2/Scenes/Lot/LotArchitecture.cs b/Assets/Scripts/OpenTS2/Scenes/Lot/LotArchitecture.cs index 738abc99..b9a77aea 100644 --- a/Assets/Scripts/OpenTS2/Scenes/Lot/LotArchitecture.cs +++ b/Assets/Scripts/OpenTS2/Scenes/Lot/LotArchitecture.cs @@ -1,4 +1,5 @@ using OpenTS2.Common; +using OpenTS2.Components; using OpenTS2.Content.DBPF; using OpenTS2.Files.Formats.DBPF; using OpenTS2.Scenes.Lot.Roof; @@ -154,27 +155,72 @@ private void Validate() } } + public T GetComponentByType(ArchitectureGameObjectTypes Type) where T : AssetReferenceComponent => Type switch + { + ArchitectureGameObjectTypes.roof => _roofComponent as T, + ArchitectureGameObjectTypes.wall => _wallComponent as T, + ArchitectureGameObjectTypes.floor => _floorComponent as T, + ArchitectureGameObjectTypes.terrain => _terrainComponent as T, + _ => default + }; + + public void InvalidateComponent(ArchitectureGameObjectTypes Type) => GetComponentByType(Type)?.Invalidate(); + /// /// Creates game objects for the lot architecture, and returns them in the provided list. /// /// List of created game objects public void CreateGameObjects(List componentList) { - var roofObj = new GameObject("roof", typeof(LotRoofComponent)); - _roofComponent = roofObj.GetComponent().CreateFromLotArchitecture(this); - componentList.Add(roofObj); - - var wall = new GameObject("wall", typeof(LotWallComponent)); - _wallComponent = wall.GetComponent().CreateFromLotArchitecture(this); - componentList.Add(wall); + // make gameobjects for each type of object on the lot + for(int type = 0; type < Enum.GetValues(typeof(ArchitectureGameObjectTypes)).Length; type++) + { + ArchitectureGameObjectTypes tType = (ArchitectureGameObjectTypes)type; + if (!CreateGameObjectsOfType(componentList, tType)) + ; // TODO: Handle if this fails + } + } - var floor = new GameObject("floor", typeof(LotFloorComponent)); - _floorComponent = floor.GetComponent().CreateFromLotArchitecture(this); - componentList.Add(floor); + public enum ArchitectureGameObjectTypes + { + roof, + wall, + floor, + terrain + } - var terrain = new GameObject("terrain", typeof(LotTerrainComponent)); - _terrainComponent = terrain.GetComponent().CreateFromLotArchitecture(this); - componentList.Add(terrain); + /// + /// Creates the correspondent GameObject for the type of geometry specified by + /// Adds it to the given component list automatically + /// + /// + /// + /// + public bool CreateGameObjectsOfType(List componentList, ArchitectureGameObjectTypes Type) + { + GameObject obj = default; + switch (Type) + { + case ArchitectureGameObjectTypes.roof: + var roofObj = obj = new GameObject("roof", typeof(LotRoofComponent)); + _roofComponent = roofObj.GetComponent().CreateFromLotArchitecture(this); + break; + case ArchitectureGameObjectTypes.wall: + var wall = obj = new GameObject("wall", typeof(LotWallComponent)); + _wallComponent = wall.GetComponent().CreateFromLotArchitecture(this); + break; + case ArchitectureGameObjectTypes.floor: + var floor = obj = new GameObject("floor", typeof(LotFloorComponent)); + _floorComponent = floor.GetComponent().CreateFromLotArchitecture(this); + break; + case ArchitectureGameObjectTypes.terrain: + var terrain = obj = new GameObject("terrain", typeof(LotTerrainComponent)); + _terrainComponent = terrain.GetComponent().CreateFromLotArchitecture(this); + break; + default: return false; + } + componentList.Add(obj); + return true; } private static int CalculateElevationIndex(int height, int x, int y) @@ -225,6 +271,6 @@ public void UpdateState(WorldState state) _roofComponent.UpdateDisplay(state); _wallComponent.UpdateDisplay(state); _floorComponent.UpdateDisplay(state); - } + } } } \ No newline at end of file diff --git a/Assets/Scripts/OpenTS2/Scenes/Lot/LotFloorComponent.cs b/Assets/Scripts/OpenTS2/Scenes/Lot/LotFloorComponent.cs index fa100332..be90cb61 100644 --- a/Assets/Scripts/OpenTS2/Scenes/Lot/LotFloorComponent.cs +++ b/Assets/Scripts/OpenTS2/Scenes/Lot/LotFloorComponent.cs @@ -24,10 +24,12 @@ public class LotFloorComponent : AssetReferenceComponent private LotArchitecture _architecture; private PatternMeshCollection _patterns; + private Dictionary> _colliders; public LotFloorComponent CreateFromLotArchitecture(LotArchitecture architecture) { _architecture = architecture; + _colliders = new Dictionary>(); LoadPatterns(); BuildFloorMeshes(); @@ -72,9 +74,9 @@ private ScenegraphMaterialDefinitionAsset GenerateMaterial(string textureName) return mat; } - private ScenegraphMaterialDefinitionAsset LoadMaterial(ContentProvider contentProvider, string name) + private ScenegraphMaterialDefinitionAsset LoadMaterial(ContentManager contentManager, string name) { - var material = contentProvider.GetAsset(new ResourceKey($"{name}_txmt", GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_TXMT)); + var material = contentManager.GetAsset(new ResourceKey($"{name}_txmt", GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_TXMT)); AddReference(material); @@ -85,8 +87,8 @@ private void LoadPatterns() { // Load the patterns. Some references are by asset name (do not exist in catalog), others are by catalog GUID. - var contentProvider = ContentProvider.Get(); - var catalogManager = CatalogManager.Get(); + var contentManager = ContentManager.Instance; + var catalogManager = CatalogManager.Instance; Dictionary patternMap = _architecture.FloorMap.Map; @@ -95,7 +97,7 @@ private void LoadPatterns() PatternDescriptor[] patterns = new PatternDescriptor[highestId + 2]; foreach (StringMapEntry entry in patternMap.Values) - { + { string materialName; if (uint.TryParse(entry.Value, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out uint guid)) { @@ -110,7 +112,7 @@ private void LoadPatterns() // Try fetch the texture using the material name. - var material = LoadMaterial(contentProvider, materialName); + var material = LoadMaterial(contentManager, materialName); patterns[entry.Id + 1] = new PatternDescriptor( materialName, @@ -136,6 +138,7 @@ private void BuildFloorMeshes() int height = patternData.Height; int eHeight = height + 1; + _colliders.Clear(); _patterns.ClearAll(); Vector3[] tileVertices = new Vector3[5]; @@ -191,11 +194,13 @@ void AddThickness(int from, int to) { if (floor == null) { - // Lazy init - don't create the floor unless it's actually being used. + // Lazy init - don't create the floor unless it's actually being used. floor = _patterns.GetFloor(i); PatternMesh thickness = floor.Get(0); thickComp = thickness.Component; } + if (!_colliders.ContainsKey(i)) + _colliders.Add(i, new HashSet()); // Pattern is present. float e0 = elevation[ei]; @@ -225,6 +230,8 @@ void AddThickness(int from, int to) comp.AddVertices(tileVertices, tileUVs); comp.AddTriangle(m1Base, 1, 0, 4); + + _colliders[i].Add(mesh1.Object.GetComponent()); } PatternMesh mesh2 = floor.Get(p.z + 1); @@ -245,6 +252,7 @@ void AddThickness(int from, int to) } comp.AddTriangle(m2Base, 2, 1, 4); + _colliders[i].Add(mesh2.Object.GetComponent()); } PatternMesh mesh3 = floor.Get(p.y + 1); @@ -269,6 +277,7 @@ void AddThickness(int from, int to) } comp.AddTriangle(m3Base, 3, 2, 4); + _colliders[i].Add(mesh3.Object.GetComponent()); } PatternMesh mesh4 = floor.Get(p.x + 1); @@ -296,7 +305,8 @@ void AddThickness(int from, int to) comp.AddVertices(tileVertices, tileUVs); } - comp.AddTriangle(m4Base, 0, 3, 4); + comp.AddTriangle(m4Base, 0, 3, 4); + _colliders[i].Add(mesh4.Object.GetComponent()); } if (i > -baseFloor) @@ -364,5 +374,12 @@ public void UpdateDisplay(WorldState state) { _patterns.UpdateDisplay(state, _architecture.BaseFloor); } + + internal bool TryGetCollidersByFloor(int floor, out IEnumerable Colliders) + { + var success = _colliders.TryGetValue(floor, out var value); + Colliders = value; // cringe out parameter doesn't do implicit casts ;_; + return success; + } } } \ No newline at end of file diff --git a/Assets/Scripts/OpenTS2/Scenes/Lot/LotLoad.cs b/Assets/Scripts/OpenTS2/Scenes/Lot/LotLoad.cs new file mode 100644 index 00000000..4588e6ef --- /dev/null +++ b/Assets/Scripts/OpenTS2/Scenes/Lot/LotLoad.cs @@ -0,0 +1,341 @@ +// JDrocks450 11-22-2023 on GitHub + +#define NEW_INVALIDATE +#undef NEW_INVALIDATE + +using OpenTS2.Common; +using OpenTS2.Content; +using OpenTS2.Content.DBPF; +using OpenTS2.Content.DBPF.Scenegraph; +using OpenTS2.Files; +using OpenTS2.Files.Formats.DBPF; +using OpenTS2.Scenes.Lot.State; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using UnityEngine; + +namespace OpenTS2.Scenes.Lot +{ + /// + /// Standard behavior for loading into the lot view. + /// Provides standard functionality for placing terrain, walls, floors, objects, etc. into the Scene + /// + public class LotLoad : MonoBehaviour + { + #region private + private WorldState _state = new WorldState(1, WallsMode.Roof); + + private string _nhood; + private int _lotId; + + private DBPFFile _lotPackage; + + private List _lotObject = new List(); + private List _testObjects = new List(); + + private RuntimeWallController _wallController = new RuntimeWallController(); + #endregion + + #region public + /// + /// Settings to dictate how the lot should be loaded + /// + public struct LotLoadSettings + { + [Flags] + public enum LotViewLayers : int + { + /// + /// Default - Do not display any architecture or objects + /// + None = 0, + /// + /// Flag - Loads terrain when set + /// + Terrain = 1, + /// + /// Flag - Loads walls when set + /// + Walls = 2, + /// + /// Flag - Loads floors when set + /// + Floors = 4, + /// + /// Flag - Loads objects when set + /// + Objects = 8 + } + /// + /// Generates the flags necessary to load all layers + /// + public const LotViewLayers AllLayers = + LotViewLayers.None | LotViewLayers.Terrain | LotViewLayers.Walls | LotViewLayers.Floors | LotViewLayers.Objects; + /// + /// Specifies which layers of the lot geometry should be loaded + /// + public LotViewLayers LoadLayers; + /// + /// Makes a new using the specified layers. + /// Default is value -- to load all layers on the lot + /// + /// + public LotLoadSettings(LotViewLayers loadLayers = AllLayers) + { + LoadLayers = loadLayers; + } + } + /// + /// (Debug) N001 + /// + public const string Default_NeighborhoodPrefix = "N001"; + /// + /// (Debug) 82 + /// + public const int Default_LotID = 82; + + /// + /// The current floor selected in the + /// + public int Floor => _state.Level; + /// + /// The current ViewMode in the + /// + /// + public WallsMode ViewMode = WallsMode.Roof; + + public int BaseFloor => Architecture?.BaseFloor ?? 0; + public int MaxFloor => Architecture?.FloorPatterns.Depth ?? 1; + /// + /// The current which indicates how the level should appear + /// Changing this directly will log in the console, but should be followed up with to ensure + /// changes can be perceived in the world. + /// + public WorldState WorldState + { + get => _state; + set + { + _state = value; + Debug.Log($"World state updated: {value}"); + } + } + + /// + /// The currently selected Neighborhood Prefix (N001 by default) + /// + public string NeighborhoodPrefix => _nhood; + /// + /// The currently selected Lot ID in the selected (82 by default) + /// + public int LotID => _lotId; + /// + /// The base that this instance used to load the scene + /// + public LotArchitecture Architecture { get; private set; } + #endregion + + /// + /// Loads the default lot + /// See: and + /// + public LotLoad() : this(Default_NeighborhoodPrefix, Default_LotID) { } + /// + /// Creates a new instance (that can be reused) with the specified Neighborhood and LotID to load + /// + /// + /// + public LotLoad(string Nhood, int LotID) + { + LoadLot(Nhood, LotID); + } + /// + /// Unloads the current lot and destroys each object instance in memory. + /// + public void UnloadLot() + { + foreach (var obj in _lotObject) + { + Destroy(obj); + } + + _lotObject.Clear(); + _testObjects.Clear(); + } + + /// + /// Updates and and loads the lot. + /// See: + /// + /// + /// + public void LoadLot(string neighborhoodPrefix, int id, LotLoadSettings Settings = default) + { + _nhood = neighborhoodPrefix; + _lotId = id; + + LoadLot(Settings); + } + /// + /// Unloads the current lot (if applicable) and loads the lot provided by + /// + /// The settings to use to load the lot + public void LoadLot(LotLoadSettings Settings = default) + { + //Unload previous session + UnloadLot(); + + var contentProvider = ContentProvider.Get(); + //Find package file for the lot given + var lotsFolderPath = Path.Combine(Filesystem.GetUserPath(), $"Neighborhoods/{NeighborhoodPrefix}/Lots"); + var lotFilename = $"{NeighborhoodPrefix}_Lot{LotID}.package"; + var lotFullPath = Path.Combine(lotsFolderPath, lotFilename); + + if (!File.Exists(lotFullPath)) + { + throw new FileNotFoundException($"LoadLot(): File not found. {lotFullPath}"); + } + + _lotPackage = contentProvider.AddPackage(lotFullPath); + + //add objects from scenegraph (primitive need to change to more robust solution later) + InvalidateObjects(); + + Architecture = new LotArchitecture(); + + Architecture.LoadFromPackage(_lotPackage); + Architecture.CreateGameObjects(_lotObject); + + ViewMode = WallsMode.Roof; // Default value is Roof + _state = new WorldState(Floor, ViewMode); + InvalidateState(); + } + /// + /// Flushes all currently loaded objects and reloads them from package + /// + public void InvalidateObjects() + { + //Clear any objects on the scene + UnloadLot(); + + var contentProvider = ContentProvider.Get(); + // Go through each lot object. + foreach (var entry in _lotPackage.Entries) + { + if (entry.GlobalTGI.TypeID != TypeIDs.LOT_OBJECT) + { + continue; + } + + try + { + var lotObject = entry.GetAsset(); + var resource = contentProvider.GetAsset( + new ResourceKey(lotObject.Object.ResourceName + "_cres", GroupIDs.Scenegraph, + TypeIDs.SCENEGRAPH_CRES)); + if (resource == null) + { + Debug.Log($"Could not find lot object: {lotObject.Object.ResourceName}"); + continue; + } + + var model = resource.CreateRootGameObject(); + model.transform.GetChild(0).localPosition = lotObject.Object.Position; + model.transform.GetChild(0).localRotation = lotObject.Object.Rotation; + + _lotObject.Add(model); + _testObjects.Add(model); + } + catch (Exception e) + { + Debug.LogException(e); + } + } + } + /// + /// Invalidates the specified group supplied by + /// + /// + void BaseInvalidateGroup(LotArchitecture.ArchitectureGameObjectTypes group) + { +#if NEW_INVALIDATE + architecture.InvalidateComponent(group); + return; +#endif + if (group == LotArchitecture.ArchitectureGameObjectTypes.roof) + { + Architecture.InvalidateComponent(group); + return; + } + //old + string objectName = group.ToString(); + //destroy existing object + var groupParent = _lotObject.Where(x => x.name == objectName).FirstOrDefault(); + if (groupParent != null) + { // clean walls + Destroy(groupParent); + _lotObject.Remove(groupParent); + } + //rebuild new mesh from memory + Architecture.CreateGameObjectsOfType(_lotObject, group); + } + + public void InvalidateFloors() + { + BaseInvalidateGroup(LotArchitecture.ArchitectureGameObjectTypes.floor); + InvalidateTerrain(); + } + public void InvalidateWalls() => BaseInvalidateGroup(LotArchitecture.ArchitectureGameObjectTypes.wall); + public void InvalidateTerrain() => BaseInvalidateGroup(LotArchitecture.ArchitectureGameObjectTypes.terrain); + + /// + /// After changing the , use this method to update the visual + /// + public void InvalidateState() + { + Architecture.UpdateState(_state); + UpdateObjectVisibility(_state.Level); + } + /// + /// Sets the given object's visibility to be Visible/Invisible + /// + /// + /// + private void SetObjectVisiblity(GameObject obj, bool visible) + { + foreach (MeshRenderer renderer in obj.GetComponentsInChildren()) + { + renderer.shadowCastingMode = visible ? UnityEngine.Rendering.ShadowCastingMode.On : UnityEngine.Rendering.ShadowCastingMode.ShadowsOnly; + } + + foreach (SkinnedMeshRenderer renderer in obj.GetComponentsInChildren()) + { + renderer.shadowCastingMode = visible ? UnityEngine.Rendering.ShadowCastingMode.On : UnityEngine.Rendering.ShadowCastingMode.ShadowsOnly; + } + } + /// + /// Sets objects to be visible based on if they should be seen by the player or not. + /// This uses the to determine up to which floor an object should be viewable. + /// + /// + private void UpdateObjectVisibility(int viewLevel) + { + foreach (GameObject obj in _testObjects) + { + int level = Architecture.GetLevelAt(obj.transform.GetChild(0).localPosition); + + SetObjectVisiblity(obj, level < viewLevel); + } + } + + /// + /// Regenerates the RoomMap from scratch. [BETA] + /// + internal void EvaluateRoomMap() + { + _wallController.GenerateAll(Architecture); + } + } +} diff --git a/Assets/Scripts/OpenTS2/Scenes/Lot/LotLoad.cs.meta b/Assets/Scripts/OpenTS2/Scenes/Lot/LotLoad.cs.meta new file mode 100644 index 00000000..f1b1675a --- /dev/null +++ b/Assets/Scripts/OpenTS2/Scenes/Lot/LotLoad.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bfcccda4cb67ae846aeffc27284e6ded +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Scenes/Lot/LotRoofComponent.cs b/Assets/Scripts/OpenTS2/Scenes/Lot/LotRoofComponent.cs index 3af192c6..f9699840 100644 --- a/Assets/Scripts/OpenTS2/Scenes/Lot/LotRoofComponent.cs +++ b/Assets/Scripts/OpenTS2/Scenes/Lot/LotRoofComponent.cs @@ -67,8 +67,8 @@ private ScenegraphMaterialDefinitionAsset GenerateMaterial(string textureName) public void LoadPatterns(uint guid) { - var contentProvider = ContentProvider.Get(); - var catalogManager = CatalogManager.Get(); + var contentManager = ContentManager.Instance; + var catalogManager = CatalogManager.Instance; CatalogRoofAsset roof = catalogManager.GetRoofById(guid); diff --git a/Assets/Scripts/OpenTS2/Scenes/Lot/LotTerrainComponent.cs b/Assets/Scripts/OpenTS2/Scenes/Lot/LotTerrainComponent.cs index 053f0894..65fbb4a4 100644 --- a/Assets/Scripts/OpenTS2/Scenes/Lot/LotTerrainComponent.cs +++ b/Assets/Scripts/OpenTS2/Scenes/Lot/LotTerrainComponent.cs @@ -47,14 +47,30 @@ public LotTerrainComponent CreateFromLotArchitecture(LotArchitecture architectur BindMaterialAndTextures(); + //Make Mesh Collider for terrain + SetTerrainCollider(_terrain.Component); + return this; } + /// + /// Adds a mesh collider matching the shape of the terrain to the current object + /// + /// + /// + private MeshCollider SetTerrainCollider(LotArchitectureMeshComponent TerrainComponent) + { + var gameobj = TerrainComponent.gameObject; + var comp = gameobj.AddComponent(); + comp.isTrigger = false; + return comp; + } + private (ScenegraphTextureAsset color, ScenegraphTextureAsset bump) LoadTexture(ContentProvider contentProvider, string name) { var result = ( - contentProvider.GetAsset(new ResourceKey($"{name}_txtr", GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_TXTR)), - contentProvider.GetAsset(new ResourceKey($"{name}-bump_txtr", GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_TXTR)) + contentManager.GetAsset(new ResourceKey($"{name}_txtr", GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_TXTR)), + contentManager.GetAsset(new ResourceKey($"{name}-bump_txtr", GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_TXTR)) ); AddReference(result.Item1, result.Item2); @@ -67,11 +83,11 @@ private void LoadLotTextures() _2DArrayView[] blendMaskData = _architecture.BlendMasks; LotTexturesAsset textures = _architecture.BlendTextures; - var contentProvider = ContentProvider.Get(); + var contentManager = ContentManager.Instance; - var baseTexture = LoadTexture(contentProvider, textures.BaseTexture); + var baseTexture = LoadTexture(contentManager, textures.BaseTexture); - _baseTexture = baseTexture.color.GetSelectedImageAsUnityTexture(contentProvider); + _baseTexture = baseTexture.color.GetSelectedImageAsUnityTexture(); var blendTextures = new (Texture2D color, Texture2D bump)[textures.BlendTextures.Length]; @@ -81,8 +97,8 @@ private void LoadLotTextures() int i = 0; foreach (string name in textures.BlendTextures) { - var texture = LoadTexture(contentProvider, name); - blendTextures[i] = (texture.color?.GetSelectedImageAsUnityTexture(contentProvider) ?? Texture2D.whiteTexture, texture.bump?.GetSelectedImageAsUnityTexture(contentProvider) ?? Texture2D.whiteTexture); + var texture = LoadTexture(contentManager, name); + blendTextures[i] = (texture.color?.GetSelectedImageAsUnityTexture() ?? Texture2D.whiteTexture, texture.bump?.GetSelectedImageAsUnityTexture() ?? Texture2D.whiteTexture); maxWidth = Math.Max(Math.Max(maxWidth, blendTextures[i].color?.width ?? 0), blendTextures[i].bump?.width ?? 0); maxHeight = Math.Max(Math.Max(maxHeight, blendTextures[i].color?.height ?? 0), blendTextures[i].bump?.height ?? 0); diff --git a/Assets/Scripts/OpenTS2/Scenes/Lot/LotWallComponent.cs b/Assets/Scripts/OpenTS2/Scenes/Lot/LotWallComponent.cs index 82e3a002..60a4844f 100644 --- a/Assets/Scripts/OpenTS2/Scenes/Lot/LotWallComponent.cs +++ b/Assets/Scripts/OpenTS2/Scenes/Lot/LotWallComponent.cs @@ -19,7 +19,7 @@ public class LotWallComponent : AssetReferenceComponent, IPatternMaterialConfigu private const string ThicknessTexture = "wall_top"; private const string FallbackMaterial = "wall_wallboard"; private const float HalfWallHeight = 1f; - private const float WallHeight = 3f; + public const float WallHeight = 3f; private const float WallsDownHeight = 0.2f; private const float YBias = 0.001f; private const float Thickness = 0.075f; @@ -65,6 +65,7 @@ public WallIntersection(WallGraphPositionEntry position) private LotArchitecture _architecture; private PatternMeshCollection _patterns; + private PatternDescriptor[] _loadedPatternDescriptions; private Dictionary _intersections; @@ -74,19 +75,24 @@ public LotWallComponent CreateFromLotArchitecture(LotArchitecture architecture) { _architecture = architecture; - LoadPatterns(); - BuildWallIntersections(); - BuildWallMeshes(); - AddFencePosts(); + Invalidate(); gameObject.transform.position = new Vector3(0, -YBias, 0); return this; } + public override void Invalidate() + { + LoadPatterns(); + BuildWallIntersections(); + BuildWallMeshes(); + AddFencePosts(); + } + private ScenegraphMaterialDefinitionAsset LoadMaterial(ContentProvider contentProvider, string name) { - var material = contentProvider.GetAsset(new ResourceKey($"{name}_txmt", GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_TXMT)); + var material = contentManager.GetAsset(new ResourceKey($"{name}_txmt", GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_TXMT)); AddReference(material); @@ -97,15 +103,29 @@ private void LoadPatterns() { // Load the patterns. Some references are by asset name (do not exist in catalog), others are by catalog GUID. - var contentProvider = ContentProvider.Get(); - var catalogManager = CatalogManager.Get(); + var contentManager = ContentManager.Instance; + var catalogManager = CatalogManager.Instance; var patternMap = _architecture.WallMap.Map; ushort highestId = patternMap.Count == 0 ? (ushort)0 : patternMap.Keys.Max(); PatternDescriptor[] patterns = new PatternDescriptor[highestId + 2]; + bool changesMade = false; + bool previousStateExisting = _loadedPatternDescriptions != null; + foreach (StringMapEntry entry in patternMap.Values) { + //Persistent data -- calls from Invalidate() will call this with data already loaded, in which case + //We can save time by not reloading the same loaded data + // TODO + if (previousStateExisting && _loadedPatternDescriptions.Length == patterns.Length && + _loadedPatternDescriptions[entry.Id + 1].Name != null) // loaded + { // PatternDescriptor is a struct -- check the name see if it's null, if not, the pattern is loaded already + patterns[entry.Id + 1] = _loadedPatternDescriptions[entry.Id + 1]; + continue; + } + changesMade = true; + string materialName; if (uint.TryParse(entry.Value, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out uint guid)) { @@ -126,7 +146,7 @@ private void LoadPatterns() // Try fetch the texture using the material name. - var material = LoadMaterial(contentProvider, materialName); + var material = LoadMaterial(contentManager, materialName); try { @@ -142,11 +162,22 @@ private void LoadPatterns() } } + if (previousStateExisting) + { + if (!changesMade) return; // no changes to wall patterns since last load + + patterns[0] = _loadedPatternDescriptions[0]; + _loadedPatternDescriptions = patterns; + _patterns.UpdatePatterns(patterns); + return; + } + patterns[0] = new PatternDescriptor( ThicknessTexture, - LoadMaterial(contentProvider, ThicknessTexture).GetAsUnityMaterial() + LoadMaterial(contentManager, ThicknessTexture).GetAsUnityMaterial() ); + _loadedPatternDescriptions = patterns; _patterns = new PatternMeshCollection(gameObject, patterns, Array.Empty(), this, _architecture.WallGraphAll.Floors); } diff --git a/Assets/Scripts/OpenTS2/Scenes/Lot/PatternMesh.cs b/Assets/Scripts/OpenTS2/Scenes/Lot/PatternMesh.cs index b31562d2..bf2b11a7 100644 --- a/Assets/Scripts/OpenTS2/Scenes/Lot/PatternMesh.cs +++ b/Assets/Scripts/OpenTS2/Scenes/Lot/PatternMesh.cs @@ -35,7 +35,7 @@ public PatternMesh(GameObject parent, string name, Material material, IPatternMa Component.EnableExtraUV(); } - Object.transform.SetParent(parent.transform); + Object.transform.SetParent(parent.transform); Component.Initialize(_material); } diff --git a/Assets/Scripts/OpenTS2/Scenes/Lot/PatternMeshCollection.cs b/Assets/Scripts/OpenTS2/Scenes/Lot/PatternMeshCollection.cs index a02c2213..9e43e498 100644 --- a/Assets/Scripts/OpenTS2/Scenes/Lot/PatternMeshCollection.cs +++ b/Assets/Scripts/OpenTS2/Scenes/Lot/PatternMeshCollection.cs @@ -54,6 +54,7 @@ public PatternMeshFloor GetFloor(int floor) public void UpdatePatterns(PatternDescriptor[] patterns) { + _patterns = patterns; foreach (var floor in _floors) { floor?.UpdatePatterns(patterns); diff --git a/Assets/Scripts/OpenTS2/Scenes/Lot/PatternMeshFloor.cs b/Assets/Scripts/OpenTS2/Scenes/Lot/PatternMeshFloor.cs index 49dd56d0..b03edb62 100644 --- a/Assets/Scripts/OpenTS2/Scenes/Lot/PatternMeshFloor.cs +++ b/Assets/Scripts/OpenTS2/Scenes/Lot/PatternMeshFloor.cs @@ -88,13 +88,13 @@ public PatternMesh Get(int id, int variantId = 0) Object, $"{descriptor.Name}_{variant.Name}", variant.MaterialTransform != null ? variant.MaterialTransform(descriptor.Material) : descriptor.Material, - _matConfig); + _matConfig); } else { result = new PatternMesh(Object, descriptor.Name, descriptor.Material, _matConfig); } - + result.Object.AddComponent(); // add collider to floors _patternMeshes[key] = result; } @@ -107,7 +107,7 @@ public FenceCollection GetFence(uint guid) if (!_fenceByGuid.TryGetValue(guid, out FenceCollection result)) { - result = new FenceCollection(ContentProvider.Get(), Object, guid); + result = new FenceCollection(ContentManager.Instance, Object, guid); _fenceByGuid[guid] = result; } diff --git a/Assets/Scripts/OpenTS2/Scenes/Lot/Room.meta b/Assets/Scripts/OpenTS2/Scenes/Lot/Room.meta new file mode 100644 index 00000000..8c428f6d --- /dev/null +++ b/Assets/Scripts/OpenTS2/Scenes/Lot/Room.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ba84f982724998349b0988abe41c5515 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Scenes/Lot/Room/RuntimeWallController.cs b/Assets/Scripts/OpenTS2/Scenes/Lot/Room/RuntimeWallController.cs new file mode 100644 index 00000000..471fb78f --- /dev/null +++ b/Assets/Scripts/OpenTS2/Scenes/Lot/Room/RuntimeWallController.cs @@ -0,0 +1,431 @@ +// JDrocks450 11-22-2023 on GitHub + +#define NEW_INVALIDATE +#undef NEW_INVALIDATE + +using OpenTS2.Content.DBPF; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Unity.Plastic.Newtonsoft.Json; +using UnityEngine; + +namespace OpenTS2.Scenes.Lot +{ + /// + /// BETA implementation. + /// Needs a lot of work to be shippable. + /// Will need to revisit this concept. + /// + internal class RuntimeWallController + { + [Serializable] + public struct GraphPlot + { + public GraphPlot(float x, float y) + { + X = x; + Y = y; + } + public float X { get; set; } + public float Y { get; set; } + } + [Serializable] + public struct GraphLine + { + public GraphLine(int fromID, int toID) + { + FromPlotID = fromID; + ToPlotID = toID; + } + + /// + /// The this line originates + /// + public int FromPlotID { get; set; } + /// + /// The this line ends at + /// + public int ToPlotID { get; set; } + + public override string ToString() => $"({FromPlotID} -> {ToPlotID})"; + } + + /// + /// A map of all positions in the WallGraph + /// For only points that are on line segments, see: + /// + public Dictionary Positions { get; private set; } = new Dictionary(); + /// + /// that are at the corners of two connected line segments + /// + public HashSet JointPositions { get; private set; } = new HashSet(); + /// + /// Lines between that form a straight wall of at least 1 unit length + /// + public Dictionary Lines { get; private set; } = new Dictionary(); + /// + /// Groups of that all form one enclosed shape (Room) on the lineplot + /// + public Dictionary> Rooms { get; private set; } = new Dictionary>(); + + /// + /// A serialized RoomState -- the current state of the walls on the lot + /// + [Serializable] + public class RoomPackage + { + public Dictionary Positions; + public HashSet JointPositions; + public Dictionary Lines; + public Dictionary> Rooms; + public int Width, Height; + } + /// + /// Simple distance formula, calculates the distance in units between two coordinates + /// + /// + /// + /// + double Distance(Vector2 p1, Vector2 p2) + { + return Math.Sqrt(Math.Pow(p1.x - p2.x, 2) + Math.Pow(p1.y - p2.y, 2)); + } + /// + /// Determines if three points create a triangle, can be used to detect straight walls versus joints + /// + /// + /// + /// + /// + bool IsTriangle(Vector2 p1, Vector2 p2, Vector2 p3) + { + // Calculate the lengths of the sides + double a = Distance(p1, p2); + double b = Distance(p2, p3); + double c = Distance(p3, p1); + + // Check if the triangle inequality theorem holds for all sides + return a + b > c && b + c > a && c + a > b; + } + /// + /// Regenerates the room map by discarding the previous data + /// + /// + public void GenerateAll(LotArchitecture architecture) + { + var graph = architecture.WallGraphAll; + Dictionary positionsData = graph.Positions; + WallGraphLineEntry[] wallData = graph.Lines; + + if (!wallData.Any()) return; + if (!positionsData.Any()) return; + + System.Diagnostics.Stopwatch debugTimer = new System.Diagnostics.Stopwatch(); + debugTimer.Start(); + + GenerateLineGraph(positionsData, wallData); + long genLineGraph = debugTimer.ElapsedMilliseconds; + debugTimer.Restart(); + + GenerateRoomMap(); + long genRoomMap = debugTimer.ElapsedMilliseconds; + debugTimer.Restart(); + + PackageRoomMap(graph.Width, graph.Height); + long genPkg = debugTimer.ElapsedMilliseconds; + debugTimer.Stop(); + + long tTime = genLineGraph + genRoomMap + genPkg; + + UnityEngine.Debug.Log($"RoomMap(): Lines took {genLineGraph}ms, Rooms took {genRoomMap}ms, Package took {genPkg}ms" + + $" and altogether took {tTime}ms. "); + //GenerateImage(positionsData, graph.Width, graph.Height); + } + + private void PackageRoomMap(int Width, int Height) + { + //Serialize this to file + using (StringWriter strJson = new StringWriter()) + { + JsonSerializer.CreateDefault().Serialize(strJson, new RoomPackage() + { + JointPositions = JointPositions, + Lines = Lines, + Positions = Positions, + Rooms = Rooms, + Width = Width, + Height = Height + }, typeof(RoomPackage)); + File.WriteAllText("C:\\Users\\xXJDr\\OneDrive\\Desktop\\roommapts2.txt", strJson.ToString()); + } + } + + /// + /// This function takes the wall graph from package and processes it into a lineplot + /// of only significant points -- as in points that form corners to build shapes. + /// This function will also create the network of lines between the points. + /// + /// + /// + private void GenerateLineGraph(Dictionary positionsData, WallGraphLineEntry[] wallData) + { + //build a map of points that are referenced by lines. + //Position ID to List of LineIDs in WallGraph + Dictionary> PositionIDReferences = new Dictionary>(); + + void AddPositionReference(int PositionID, int LayerID) + { + //Check if the point exists in our wall graph + if (!positionsData.ContainsKey(PositionID)) return; + //position existing + if (PositionIDReferences.TryGetValue(PositionID, out HashSet references)) + references.Add(LayerID); + else + { + PositionIDReferences.Add(PositionID, new HashSet() { LayerID }); + if (!Positions.ContainsKey(PositionID)) + Positions.Add(PositionID, new GraphPlot(positionsData[PositionID].XPos, + positionsData[PositionID].YPos)); + } + } + + //find all points that are referenced by wall lines + foreach (var wall in wallData) + { + AddPositionReference(wall.FromId, wall.LayerId); + AddPositionReference(wall.ToId, wall.LayerId); + } + + //map lines to their layerIds + Dictionary lineMap = new Dictionary(); + foreach (var line in wallData) + lineMap.Add(line.LayerId, line); + + List processed = new List(); + HashSet WallLayerIDsOnLine = new HashSet(); + Lines.Clear(); + + //filter out positions that form straight lines to get a + //lineplot of all significant points -- e.g. the ones that form + //corners + //-- + //This is done by taking two connected wall lines and seeing if all three points + //on these two lines form a triangle with any area -- if they do, it's a bend + foreach (var positionItem in PositionIDReferences) + { + if (positionItem.Value.Count <= 1) // 1 or less connections can never form a wall + continue; // this is due to them being open-ended + else if (positionItem.Value.Count == 2 && processed.Contains(positionItem.Key)) + continue; // only two connections means it's already been processed and cannot be anything more + + int lineFrom = -1, lineTo = -1; + + //tunnelling function -- watch out for stack overflow by using cautiously + //keep scope to only one level on the lot at a time, and this function tree will + //end as soon as a line segment is found + // -- todo: set limit on tunnelling level to be diagonal line from lot corner to corner + void Try(int meID, int tunneled) + { + if (JointPositions.Contains(meID)) + { // already a joint -- don't bother with the detection + lineTo = meID; + return; + } + var references = PositionIDReferences[meID]; // find all wall lines that contain this point + if (references.Count <= 1) goto exit; // none references!! + if (references.Count > 2) + { + JointPositions.Add(meID); + lineTo = meID; + if (tunneled == 0) + return; + } + //very bad -- change ASAP + WallGraphLineEntry line1 = lineMap[references.ElementAt(0)]; + WallGraphLineEntry line2 = lineMap[references.ElementAt(1)]; + int other1 = line1.ToId == meID ? line1.FromId : line1.ToId; // which end isn't the current point? + if (other1 == meID) + goto exit; // catastropic error -- both ends are the same and also this point... how would this happen? + int other2 = line2.ToId == meID ? line2.FromId : line2.ToId; // which end isn't the current point or other point? + if (other2 == meID) + goto exit; // catastropic error -- see above + if (other1 == other2) + goto exit; // catastropic error -- see above + + //form a triangle using all three points + Vector2 pos1 = new Vector2(positionsData[other1].XPos, positionsData[other1].YPos); + Vector2 pos2 = new Vector2(positionsData[other2].XPos, positionsData[other2].YPos); + Vector2 center = new Vector2(positionsData[meID].XPos, positionsData[meID].YPos); + + //check if this is a bend -- has an area + if (!IsTriangle(center, pos1, pos2)) + { + processed.Add(meID); // point is spent + int next = processed.Contains(other2) ? other1 : other2; // pick the point we haven't visited yet + if (lineFrom == -1) + lineFrom = next == other2 ? other1 : other2; // from point is the origin point + Try(next, tunneled + 1); // tunnel until bend is found to complete the segment + return; + } + //found a bend ... close and complete this tunnel + JointPositions.Add(meID); + lineTo = meID; + return; + exit:; + } + + lineFrom = lineTo = -1; + //begin -- walk the current line until it finds a bend + //adds what it finds to Lines if it is indeed a line + //also adds to Joints collection + Try(positionItem.Key, 0); + + if (lineFrom != -1 && lineTo != -1 && lineFrom != lineTo) + Lines.Add(Lines.Count + 1, new GraphLine(lineFrom, lineTo)); + } + } + + /// + /// This function will walk the lineplot created during + /// finding lines that connect to one another to form shapes making up enclosed spaces. + /// + private void GenerateRoomMap() + { + IDictionary> dirtyRooms = new Dictionary>(); + Stack currentlyVisitingRoomPositions = new Stack(); + + foreach (var line in Lines) + { + int findingPositionID = line.Value.FromPlotID; + bool FindRoom(int currentLineID, int fromPositionID) + { + currentlyVisitingRoomPositions.Push(currentLineID); + var lineValue = Lines[currentLineID]; + var nextPoint = lineValue.ToPlotID != fromPositionID ? lineValue.ToPlotID : lineValue.FromPlotID; + if (nextPoint == findingPositionID) + { + //found a room + int[] points = currentlyVisitingRoomPositions.ToArray(); + //ensure room is valid + //AssertRoomValid(points); + //does this room already exist -- also calls AssertRoomValid() + if (!RoomExisting(-1, dirtyRooms, points)) + dirtyRooms.Add(dirtyRooms.Count + 1, points); // doesn't, add it + return true; + } + var results = Lines.Where(x => x.Value.FromPlotID == nextPoint || x.Value.ToPlotID == nextPoint); + int nextLineID = -1; + foreach (var result in results) + { + if (result.Key == currentLineID) continue; + nextLineID = result.Key; + } + if (nextLineID == -1) return false; + return FindRoom(nextLineID, nextPoint); + } + currentlyVisitingRoomPositions.Clear(); + FindRoom(line.Key, findingPositionID); + } + + Rooms.Clear(); + foreach(var item in dirtyRooms) + Rooms.Add(item.Key, item.Value); + } + + /// + /// Assures the supplied set of points can make a valid room. + /// + /// + /// + /// + public void AssertRoomValid(params int[] RoomPoints) + { + if (RoomPoints == default) + throw new NullReferenceException("RoomPoints passed as null reference."); + if (RoomPoints.Length < 4) + throw new InvalidDataException($"Rooms must have at least four points. This one supplied has {RoomPoints.Length}"); + } + + /// + /// Tests to see if the given room exists in + /// Supplying the RoomID will ensure the current room isn't compared to itself in the map. + /// It is determined to be the same room if all the points supplied match all the points on a given + /// Room in the room map. + /// + /// + /// + /// + public bool RoomExisting(int RoomID, params int[] RoomPoints) => RoomExisting(RoomID, Rooms, RoomPoints); + + /// + /// Tests to see if the given room exists in + /// Supplying the RoomID will ensure the current room isn't compared to itself in the map. + /// It is determined to be the same room if all the points supplied match all the points on a given + /// Room in the room map. + /// + /// + /// + /// + public bool RoomExisting(int RoomID, IDictionary> RoomCollection, params int[] RoomPoints) + { + AssertRoomValid(RoomPoints); + bool duplicate = false; + foreach (var otherRoom in RoomCollection) + { + if (otherRoom.Key == RoomID) + continue; // same as the room I'm comparing + if (otherRoom.Value.Count() != RoomPoints.Length) + continue; // not the same number of points + foreach (var point in otherRoom.Value) + { + duplicate = RoomPoints.Contains(point); + if (!duplicate) break; + } + if (duplicate) break; + } + return duplicate; + } + + public void GenerateImage(string exportFileName, Dictionary positionsData, int Width, int Height) + { + Texture2D roomMap = new Texture2D(Width, Height); + + Color[] colors = new Color[] { + Color.green, + Color.cyan, + Color.magenta, + Color.grey, + Color.yellow, + Color.blue + }; + + foreach (var drawLine in Lines.Values) + { + var position = positionsData[drawLine.FromPlotID]; + roomMap.SetPixel((int)position.XPos, (int)position.YPos, Color.red); + position = positionsData[drawLine.ToPlotID]; + roomMap.SetPixel((int)position.XPos, (int)position.YPos, Color.red); + } + + int index = -1; + foreach (var room in Rooms) + { + index++; + + Color drawColor = colors[index]; + foreach (var lineID in room.Value) + { + var drawLine = Lines[lineID]; + var position = positionsData[drawLine.FromPlotID]; + roomMap.SetPixel((int)position.XPos, (int)position.YPos, drawColor); + position = positionsData[drawLine.ToPlotID]; + roomMap.SetPixel((int)position.XPos, (int)position.YPos, drawColor); + } + } + + File.WriteAllBytes(exportFileName, roomMap.EncodeToPNG()); + } + } +} diff --git a/Assets/Scripts/OpenTS2/Scenes/Lot/Room/RuntimeWallController.cs.meta b/Assets/Scripts/OpenTS2/Scenes/Lot/Room/RuntimeWallController.cs.meta new file mode 100644 index 00000000..eae74992 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Scenes/Lot/Room/RuntimeWallController.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 989c8164467e1524d9013a6579681d65 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Scenes/Lot/State/WorldState.cs b/Assets/Scripts/OpenTS2/Scenes/Lot/State/WorldState.cs index 6ba48144..dc6770ea 100644 --- a/Assets/Scripts/OpenTS2/Scenes/Lot/State/WorldState.cs +++ b/Assets/Scripts/OpenTS2/Scenes/Lot/State/WorldState.cs @@ -18,5 +18,10 @@ public WorldState(int level, WallsMode walls) Level = level; Walls = walls; } + + public override string ToString() + { + return $"Walls: {Walls}, Level: {Level}"; + } } } \ No newline at end of file diff --git a/Assets/Scripts/OpenTS2/Scenes/StartupController.cs b/Assets/Scripts/OpenTS2/Scenes/MainMenuController.cs similarity index 51% rename from Assets/Scripts/OpenTS2/Scenes/StartupController.cs rename to Assets/Scripts/OpenTS2/Scenes/MainMenuController.cs index c60c68e1..9156b938 100644 --- a/Assets/Scripts/OpenTS2/Scenes/StartupController.cs +++ b/Assets/Scripts/OpenTS2/Scenes/MainMenuController.cs @@ -15,19 +15,16 @@ using System.Collections; using OpenTS2.UI.Layouts; using OpenTS2.Lua; +using OpenTS2.Engine; namespace OpenTS2.Scenes { - public class StartupController : MonoBehaviour + public class MainMenuController : MonoBehaviour { - public static bool GameLoaded = false; public float FadeOutTime = 1f; public UIBMPComponent InitialLoadScreenBackgroundImage; public UIBMPComponent InitialLoadScreenLogoImage; public ReiaPlayer InitialLoadScreenReiaPlayer; - public bool EnableReia = true; - public bool LoadObjects = true; - public bool StreamReia = true; private ResourceKey _initialLoadScreenReiaKey = new ResourceKey(0x8DA3ADE7, 0x499DB772, TypeIDs.UI); private ResourceKey _initialLoadScreenBackgroundKey = new ResourceKey(0xCCC9AF80, 0x499DB772, TypeIDs.IMG); private ResourceKey _initialLoadScreenLogoKey = new ResourceKey(0x8CBB9323, 0x499DB772, TypeIDs.IMG); @@ -36,52 +33,33 @@ public class StartupController : MonoBehaviour private void Start() { - if (!GameLoaded) + var contentManager = ContentManager.Instance; + ContentLoading.LoadContentStartup(); + if (InitialLoadScreenReiaPlayer != null) { - var contentProvider = ContentProvider.Get(); - ContentLoading.LoadContentStartup(); - PluginSupport.Initialize(); - if (EnableReia) - { - if (InitialLoadScreenReiaPlayer != null) - { - InitialLoadScreenReiaPlayer.SetReia(_initialLoadScreenReiaKey, StreamReia); - InitialLoadScreenReiaPlayer.Speed = 0f; - } - } - else - InitialLoadScreenReiaPlayer.gameObject.SetActive(false); - if (InitialLoadScreenBackgroundImage != null) - { - var bgAsset = contentProvider.GetAsset(_initialLoadScreenBackgroundKey); - if (bgAsset != null) - { - InitialLoadScreenBackgroundImage.SetTexture(bgAsset); - InitialLoadScreenBackgroundImage.SetNativeSize(); - } - } - if (InitialLoadScreenLogoImage != null) + InitialLoadScreenReiaPlayer.SetReia(_initialLoadScreenReiaKey, true); + InitialLoadScreenReiaPlayer.Speed = 0f; + } + if (InitialLoadScreenBackgroundImage != null) + { + var bgAsset = contentManager.GetAsset(_initialLoadScreenBackgroundKey); + if (bgAsset != null) { - var fgAsset = contentProvider.GetAsset(_initialLoadScreenLogoKey); - if (fgAsset != null) - { - InitialLoadScreenLogoImage.SetTexture(fgAsset); - InitialLoadScreenLogoImage.SetNativeSize(); - } + InitialLoadScreenBackgroundImage.SetTexture(bgAsset); + InitialLoadScreenBackgroundImage.SetNativeSize(); } - ContentLoading.LoadGameContentAsync(_loadProgress).ContinueWith((task) => { OnFinishLoading(); }, TaskScheduler.FromCurrentSynchronizationContext()); } - else + if (InitialLoadScreenLogoImage != null) { - OnFinishLoading(); - if (InitialLoadScreenBackgroundImage != null) - Destroy(InitialLoadScreenBackgroundImage.gameObject); - if (InitialLoadScreenLogoImage != null) - Destroy(InitialLoadScreenLogoImage.gameObject); - if (InitialLoadScreenReiaPlayer != null) - Destroy(InitialLoadScreenReiaPlayer.gameObject); + var fgAsset = contentManager.GetAsset(_initialLoadScreenLogoKey); + if (fgAsset != null) + { + InitialLoadScreenLogoImage.SetTexture(fgAsset); + InitialLoadScreenLogoImage.SetNativeSize(); + } } - MusicController.PlayMusic(AudioManager.SplashAudio); + ContentLoading.LoadGameContentAsync(_loadProgress).ContinueWith((task) => { OnFinishLoading(); }, TaskScheduler.FromCurrentSynchronizationContext()); + Core.OnBeginLoading?.Invoke(); } private void Update() @@ -107,30 +85,18 @@ private void Update() private void OnFinishLoading() { - var luaMgr = LuaManager.Get(); - luaMgr.InitializeObjectScripts(); - CursorController.Cursor = CursorController.CursorType.Hourglass; - if (LoadObjects && !GameLoaded) - { - var oMgr = ObjectManager.Get(); - oMgr.Initialize(); - - EffectsManager.Get().Initialize(); - } - if (!GameLoaded) - NeighborhoodManager.Initialize(); - CursorController.Cursor = CursorController.CursorType.Default; - Debug.Log("All loaded"); - FadeOutLoading(); try { + CursorController.Cursor = CursorController.CursorType.Hourglass; + Core.OnFinishedLoading?.Invoke(); + CursorController.Cursor = CursorController.CursorType.Default; + FadeOutLoading(); var mainMenu = new MainMenu(); } catch(Exception e) { - Debug.Log(e.ToString()); + Debug.LogError(e); } - GameLoaded = true; } void FadeOutLoading() diff --git a/Assets/Scripts/OpenTS2/Scenes/StartupController.cs.meta b/Assets/Scripts/OpenTS2/Scenes/MainMenuController.cs.meta similarity index 100% rename from Assets/Scripts/OpenTS2/Scenes/StartupController.cs.meta rename to Assets/Scripts/OpenTS2/Scenes/MainMenuController.cs.meta diff --git a/Assets/Scripts/OpenTS2/Scenes/NeighborhoodController.cs b/Assets/Scripts/OpenTS2/Scenes/NeighborhoodController.cs index ef0964e2..d8bb04c8 100644 --- a/Assets/Scripts/OpenTS2/Scenes/NeighborhoodController.cs +++ b/Assets/Scripts/OpenTS2/Scenes/NeighborhoodController.cs @@ -1,4 +1,6 @@ using OpenTS2.Content; +using OpenTS2.Engine; +using OpenTS2.Game; using OpenTS2.UI.Layouts; using System.Collections; using System.Collections.Generic; @@ -11,7 +13,14 @@ public class NeighborhoodController : MonoBehaviour // Start is called before the first frame update void Start() { + Core.OnNeighborhoodEntered?.Invoke(); var hud = new NeighborhoodHUD(); + var simulator = Simulator.Instance; + if (simulator != null) + simulator.Kill(); + ObjectManager.Create(); + NeighborManager.Create(); + Simulator.Create(Simulator.Context.Neighborhood); } } } diff --git a/Assets/Scripts/OpenTS2/Scenes/NeighborhoodDecorations.cs b/Assets/Scripts/OpenTS2/Scenes/NeighborhoodDecorations.cs index 9b358672..60cbc5f6 100644 --- a/Assets/Scripts/OpenTS2/Scenes/NeighborhoodDecorations.cs +++ b/Assets/Scripts/OpenTS2/Scenes/NeighborhoodDecorations.cs @@ -18,8 +18,8 @@ namespace OpenTS2.Scenes { public class NeighborhoodDecorations : AssetReferenceComponent { - [ConsoleProperty("ots2_HoodBatching")] - private static bool s_enableBatching = true; + [GameProperty(false)] + private static bool EnableBatching = false; private Dictionary _roadMaterialLookup = new Dictionary(); private Transform _decorationsParent; private Transform _roadsParent; @@ -34,7 +34,7 @@ void Start() _roadsParent.SetParent(transform); _lotsParent.SetParent(transform); - var decorations = NeighborhoodManager.CurrentNeighborhood.Decorations; + var decorations = NeighborhoodManager.Instance.CurrentNeighborhood.Decorations; // Render trees. RenderDecorationWithModels(decorations.FloraDecorations); @@ -49,7 +49,7 @@ void Start() RenderDecorationWithModels(decorations.PropDecorations); // Render lot imposters. - foreach (var lot in NeighborhoodManager.CurrentNeighborhood.Lots) + foreach (var lot in NeighborhoodManager.Instance.CurrentNeighborhood.Lots) { try { @@ -62,7 +62,7 @@ void Start() } } - if (s_enableBatching) + if (EnableBatching) { var batchedDeco = Batching.Batch(_decorationsParent, flipFaces: true); var batchedLots = Batching.Batch(_lotsParent, flipFaces: true); @@ -81,7 +81,7 @@ private void OnDestroy() private void RenderRoad(RoadDecoration road) { - var roadTextureUnformatted = NeighborhoodManager.CurrentNeighborhood.Terrain.TerrainType.RoadTextureName; + var roadTextureUnformatted = NeighborhoodManager.Instance.CurrentNeighborhood.Terrain.TerrainType.RoadTextureName; var roadTextureName = road.GetTextureName(roadTextureUnformatted); var roadObject = new GameObject("road", typeof(MeshFilter), typeof(MeshRenderer)) { @@ -91,6 +91,7 @@ private void RenderRoad(RoadDecoration road) parent = _roadsParent } }; + roadObject.layer = Layers.NonReflective; var roadMesh = new Mesh(); roadMesh.SetVertices(road.RoadCorners); @@ -103,12 +104,13 @@ private void RenderRoad(RoadDecoration road) roadMesh.SetUVs(0, uvs); // TODO - Make this smoother, maybe generate a low res normal map from the terrain height map or calculate normals ourselves. - roadMesh.RecalculateNormals(); + // roadMesh.RecalculateNormals(); + roadMesh.SetNormals(new[] { Vector3.up, Vector3.up, Vector3.up, Vector3.up }); roadObject.GetComponent().sharedMesh = roadMesh; if (!_roadMaterialLookup.TryGetValue(roadTextureName, out Material roadMaterial)) { - var texture = ContentProvider.Get().GetAsset(new ResourceKey(roadTextureName, + var texture = ContentManager.Instance.GetAsset(new ResourceKey(roadTextureName, GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_TXTR)); if (texture == null) @@ -119,7 +121,7 @@ private void RenderRoad(RoadDecoration road) roadMaterial = new Material(Shader.Find("OpenTS2/Road")) { - mainTexture = texture.GetSelectedImageAsUnityTexture(ContentProvider.Get()) + mainTexture = texture.GetSelectedImageAsUnityTexture() }; roadMaterial.mainTexture.wrapMode = TextureWrapMode.Clamp; @@ -204,7 +206,7 @@ private void RenderBridges(IEnumerable bridges) { // Render the road // RenderRoad(bridge.Road) - var model = ContentProvider.Get().GetAsset(new ResourceKey(bridge.ResourceName, + var model = ContentManager.Instance.GetAsset(new ResourceKey(bridge.ResourceName, GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_CRES)); var bridgeObject = model.CreateRootGameObject(); @@ -223,13 +225,13 @@ private void RenderDecorationWithModels(IEnumerable deco { foreach (var decoration in decorations) { - if (!NeighborhoodManager.NeighborhoodObjects.TryGetValue(decoration.ObjectId, out var resourceName)) + if (!NeighborhoodManager.Instance.NeighborhoodObjects.TryGetValue(decoration.ObjectId, out var resourceName)) { Debug.Log($"Can't find model for decoration with guid 0x{decoration.ObjectId:X}"); return; } - var model = ContentProvider.Get().GetAsset(new ResourceKey(resourceName, + var model = ContentManager.Instance.GetAsset(new ResourceKey(resourceName, GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_CRES)); var decorationObject = model.CreateRootGameObject(); diff --git a/Assets/Scripts/OpenTS2/Scenes/NeighborhoodTerrain.cs b/Assets/Scripts/OpenTS2/Scenes/NeighborhoodTerrain.cs index e1729cd4..a46a8418 100644 --- a/Assets/Scripts/OpenTS2/Scenes/NeighborhoodTerrain.cs +++ b/Assets/Scripts/OpenTS2/Scenes/NeighborhoodTerrain.cs @@ -19,9 +19,9 @@ public class NeighborhoodTerrain : AssetReferenceComponent { public static NeighborhoodTerrain Instance; public Transform Sun; - private static ResourceKey s_matCapKey = new ResourceKey(0x0BE702EF, 0x8BA01057, TypeIDs.IMG); - private static ResourceKey s_cliffKey = new ResourceKey(0xFFF56CAE, 0x6E80B6A1, GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_TXTR); - private static ResourceKey s_shoreKey = new ResourceKey("nh-test-beach_txtr", GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_TXTR); + private static ResourceKey MatCapKey = new ResourceKey(0x0BE702EF, 0x8BA01057, TypeIDs.IMG); + private static ResourceKey CliffKey = new ResourceKey(0xFFF56CAE, 0x6E80B6A1, GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_TXTR); + private static ResourceKey ShoreKey = new ResourceKey("nh-test-beach_txtr", GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_TXTR); //private static ResourceKey TemperateWetKey = new ResourceKey(0xFF354609, 0x1A9C59CC, 0x1C0532FA, TypeIDs.SCENEGRAPH_TXTR); private Material _terrainMaterial; private MeshFilter _meshFilter; @@ -30,40 +30,40 @@ void Awake() { Instance = this; - var terrain = NeighborhoodManager.CurrentNeighborhood.Terrain; + var terrain = NeighborhoodManager.Instance.CurrentNeighborhood.Terrain; var terrainType = terrain.TerrainType; _meshFilter = GetComponent(); - var contentProvider = ContentProvider.Get(); + var contentManager = ContentManager.Instance; var meshRenderer = GetComponent(); // Using .material here cause i want to instantiate it _terrainMaterial = meshRenderer.material; _terrainMaterial.shader = terrainType.TerrainShader; _terrainMaterial.SetVector("_LightVector", Sun.forward); - var matCap = contentProvider.GetAsset(s_matCapKey); - var smooth = contentProvider.GetAsset(terrainType.Texture); - var variation1 = contentProvider.GetAsset(terrainType.Texture1); - var variation2 = contentProvider.GetAsset(terrainType.Texture2); - var cliff = contentProvider.GetAsset(s_cliffKey); - var shore = contentProvider.GetAsset(s_shoreKey); - var roughness = contentProvider.GetAsset(terrainType.Roughness); - var roughness1 = contentProvider.GetAsset(terrainType.Roughness1); - var roughness2 = contentProvider.GetAsset(terrainType.Roughness2); + var matCap = contentManager.GetAsset(MatCapKey); + var smooth = contentManager.GetAsset(terrainType.Texture); + var variation1 = contentManager.GetAsset(terrainType.Texture1); + var variation2 = contentManager.GetAsset(terrainType.Texture2); + var cliff = contentManager.GetAsset(CliffKey); + var shore = contentManager.GetAsset(ShoreKey); + var roughness = contentManager.GetAsset(terrainType.Roughness); + var roughness1 = contentManager.GetAsset(terrainType.Roughness1); + var roughness2 = contentManager.GetAsset(terrainType.Roughness2); AddReference(matCap, smooth, variation1, variation2, cliff, shore, roughness1, roughness2); if (matCap != null) { matCap.Texture.wrapMode = TextureWrapMode.Clamp; _terrainMaterial.SetTexture("_MatCap", matCap.Texture); } - _terrainMaterial.mainTexture = smooth.GetSelectedImageAsUnityTexture(contentProvider); - _terrainMaterial.SetTexture("_Variation1", variation1.GetSelectedImageAsUnityTexture(contentProvider)); - _terrainMaterial.SetTexture("_Variation2", variation2.GetSelectedImageAsUnityTexture(contentProvider)); - _terrainMaterial.SetTexture("_CliffTex", cliff.GetSelectedImageAsUnityTexture(contentProvider)); - _terrainMaterial.SetTexture("_Shore", shore.GetSelectedImageAsUnityTexture(contentProvider)); - _terrainMaterial.SetTexture("_Roughness", roughness.GetSelectedImageAsUnityTexture(contentProvider)); - _terrainMaterial.SetTexture("_Roughness1", roughness1.GetSelectedImageAsUnityTexture(contentProvider)); - _terrainMaterial.SetTexture("_Roughness2", roughness2.GetSelectedImageAsUnityTexture(contentProvider)); + _terrainMaterial.mainTexture = smooth.GetSelectedImageAsUnityTexture(); + _terrainMaterial.SetTexture("_Variation1", variation1.GetSelectedImageAsUnityTexture()); + _terrainMaterial.SetTexture("_Variation2", variation2.GetSelectedImageAsUnityTexture()); + _terrainMaterial.SetTexture("_CliffTex", cliff.GetSelectedImageAsUnityTexture()); + _terrainMaterial.SetTexture("_Shore", shore.GetSelectedImageAsUnityTexture()); + _terrainMaterial.SetTexture("_Roughness", roughness.GetSelectedImageAsUnityTexture()); + _terrainMaterial.SetTexture("_Roughness1", roughness1.GetSelectedImageAsUnityTexture()); + _terrainMaterial.SetTexture("_Roughness2", roughness2.GetSelectedImageAsUnityTexture()); SetTerrainMesh(); } @@ -75,7 +75,7 @@ private void OnDestroy() void SetTerrainMesh() { - var terrainAsset = NeighborhoodManager.CurrentNeighborhood.Terrain; + var terrainAsset = NeighborhoodManager.Instance.CurrentNeighborhood.Terrain; var terrainMesh = terrainAsset.MakeMesh(); var meshCollider = GetComponent(); var meshRenderer = GetComponent(); @@ -143,12 +143,12 @@ void InitializeVertexColors(Mesh terrainMesh) // TODO: Optimize, maybe multithread. void MakeRoughness(Mesh terrainMesh) { - var terrainType = NeighborhoodManager.CurrentNeighborhood.Terrain.TerrainType; + var terrainType = NeighborhoodManager.Instance.CurrentNeighborhood.Terrain.TerrainType; var roadDistanceForRoughness = terrainType.RoadDistanceForRoughness; var roughnessFalloff = terrainType.RoughnessFalloff; var vertices = terrainMesh.vertices; var colors = terrainMesh.colors; - var roads = NeighborhoodManager.CurrentNeighborhood.Decorations.RoadDecorations; + var roads = NeighborhoodManager.Instance.CurrentNeighborhood.Decorations.RoadDecorations; for (var i = 0; i < vertices.Length; i++) { var vertex = vertices[i]; diff --git a/Assets/Scripts/OpenTS2/Scenes/NeighborhoodWater.cs b/Assets/Scripts/OpenTS2/Scenes/NeighborhoodWater.cs index 96357416..3fe6c74f 100644 --- a/Assets/Scripts/OpenTS2/Scenes/NeighborhoodWater.cs +++ b/Assets/Scripts/OpenTS2/Scenes/NeighborhoodWater.cs @@ -13,7 +13,7 @@ public class NeighborhoodWater : MonoBehaviour private void Start() { - transform.position += NeighborhoodManager.CurrentNeighborhood.Terrain.SeaLevel * Vector3.up; + transform.position += NeighborhoodManager.Instance.CurrentNeighborhood.Terrain.SeaLevel * Vector3.up; if (CameraReflection.Instance != null) { var meshRenderer = GetComponent(); diff --git a/Assets/Scripts/OpenTS2/Scenes/ParticleEffects/SwarmDecal.cs b/Assets/Scripts/OpenTS2/Scenes/ParticleEffects/SwarmDecal.cs index 5d810bf7..f4b75a74 100644 --- a/Assets/Scripts/OpenTS2/Scenes/ParticleEffects/SwarmDecal.cs +++ b/Assets/Scripts/OpenTS2/Scenes/ParticleEffects/SwarmDecal.cs @@ -16,19 +16,16 @@ namespace OpenTS2.Scenes.ParticleEffects { public class SwarmDecal : MonoBehaviour { - [ConsoleProperty("enableDecals")] - private static bool s_enableDecals = true; - private static int s_location = Shader.PropertyToID("_Location"); - private static int s_rotation = Shader.PropertyToID("_Rotation"); + private static int Location = Shader.PropertyToID("_Location"); + private static int Rotation = Shader.PropertyToID("_Rotation"); private ScenegraphTextureAsset _textureAsset; private Vector3 _position; private Vector3 _rotation; private Material _material; + private Mesh _decalMesh; private void Start() { - if (!s_enableDecals) - return; _position = transform.position; _rotation = transform.rotation.eulerAngles; Initialize(); @@ -36,7 +33,7 @@ private void Start() public void SetDecal(DecalEffect effect) { - _textureAsset = ContentProvider.Get().GetAsset(new ResourceKey($"{effect.TextureName}_txtr", GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_TXTR)); + _textureAsset = ContentManager.Instance.GetAsset(new ResourceKey($"{effect.TextureName}_txtr", GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_TXTR)); } public void Initialize() @@ -51,12 +48,11 @@ public void Initialize() var meshFilter = GetComponent(); var meshRenderer = GetComponent(); - meshFilter.sharedMesh = terrainMeshFilter.sharedMesh; + BuildDecalMesh(terrainMeshFilter.sharedMesh); + meshFilter.sharedMesh = _decalMesh; - _material = new Material(Shader.Find("OpenTS2/NeighborhoodDecal")); - _material.mainTexture = _textureAsset.GetSelectedImageAsUnityTexture(ContentProvider.Get()); - _material.SetVector(s_location, _position); - _material.SetVector(s_rotation, _rotation); + _material = new Material(Shader.Find("OpenTS2/BakedDecal")); + _material.mainTexture = _textureAsset.GetSelectedImageAsUnityTexture(); meshRenderer.sharedMaterial = _material; transform.SetParent(null); @@ -65,10 +61,64 @@ public void Initialize() transform.localScale = Vector3.one; } + private void BuildDecalMesh(Mesh terrainMesh) + { + _decalMesh = new Mesh(); + var vertices = terrainMesh.vertices; + var uvs = new Vector2[terrainMesh.vertices.Length]; + + var oTriangles = terrainMesh.triangles; + var triangles = new List(); + + var radius = 80f; + var radiusHalf = radius * 0.5f; + var decalPositionMatrix = Matrix4x4.Translate(new Vector3(-_position.x + radiusHalf, 0f, -_position.z + radiusHalf)); + var decalRotationMatrix = Matrix4x4.Rotate(Quaternion.Euler(0f, -_rotation.y, 0f)); + + for(var i = 0; i < vertices.Length; i++) + { + var v = decalPositionMatrix.MultiplyPoint(vertices[i]); + v /= radius; + v.x -= 0.5f; + v.z -= 0.5f; + v = decalRotationMatrix.MultiplyPoint(v); + v.x += 0.5f; + v.z += 0.5f; + + uvs[i] = new Vector2(v.x, v.z); + } + + for (var i = 0; i < oTriangles.Length; i += 3) + { + var v1i = oTriangles[i]; + var v2i = oTriangles[i + 1]; + var v3i = oTriangles[i + 2]; + + var v1 = uvs[v1i]; + var v2 = uvs[v2i]; + var v3 = uvs[v3i]; + + if ((v1.x < 1f && v1.y < 1f && v1.x > 0f && v1.y > 0f) || + (v2.x < 1f && v2.y < 1f && v2.x > 0f && v2.y > 0f) || + (v3.x < 1f && v3.y < 1f && v3.x > 0f && v3.y > 0f)) + { + triangles.Add(v1i); + triangles.Add(v2i); + triangles.Add(v3i); + } + } + + _decalMesh.SetVertices(vertices); + _decalMesh.SetUVs(0, uvs); + _decalMesh.SetTriangles(triangles, 0); + } + private void OnDestroy() { if (_material != null) _material.Free(); + if (_decalMesh != null) + _decalMesh.Free(); } } } diff --git a/Assets/Scripts/OpenTS2/Scenes/ParticleEffects/SwarmMetaParticleSystem.cs b/Assets/Scripts/OpenTS2/Scenes/ParticleEffects/SwarmMetaParticleSystem.cs index 5d65bbd8..fb6a8b70 100644 --- a/Assets/Scripts/OpenTS2/Scenes/ParticleEffects/SwarmMetaParticleSystem.cs +++ b/Assets/Scripts/OpenTS2/Scenes/ParticleEffects/SwarmMetaParticleSystem.cs @@ -34,7 +34,7 @@ public void SetModelBaseEffect(MetaParticle effect, ModelEffect baseModelEffect) // Kinda hacky but for now we just render out the scenegraph and get the first mesh and material out of it. // Unity's built-in particle system can't spawn full GameObjects but it can handle meshes. - _model = ContentProvider.Get().GetAsset(new ResourceKey(baseModelEffect.ModelName, + _model = ContentManager.Instance.GetAsset(new ResourceKey(baseModelEffect.ModelName, GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_CRES)); var modelObject = _model.CreateRootGameObject(); modelObject.SetActive(false); diff --git a/Assets/Scripts/OpenTS2/Scenes/ParticleEffects/SwarmParticleSystem.cs b/Assets/Scripts/OpenTS2/Scenes/ParticleEffects/SwarmParticleSystem.cs index 107fbd3a..c2fe7558 100644 --- a/Assets/Scripts/OpenTS2/Scenes/ParticleEffects/SwarmParticleSystem.cs +++ b/Assets/Scripts/OpenTS2/Scenes/ParticleEffects/SwarmParticleSystem.cs @@ -43,7 +43,7 @@ public void SetVisualEffect(SwarmVisualEffect visualEffect, EffectsAsset effects metaParticleSystem.transform.SetParent(transform, worldPositionStays: false); break; case ModelEffect e: - var model = ContentProvider.Get() + var model = ContentManager.Instance .GetAsset(new ResourceKey(e.ModelName, GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_CRES)); var modelObject = model.CreateGameObject(); @@ -122,10 +122,10 @@ internal static void SetParticleParameters(ParticleSystem system, GameObject par if (effect.Drawing.MaterialName != "") { - var textureAsset = ContentProvider.Get().GetAsset(new ResourceKey( + var textureAsset = ContentManager.Instance.GetAsset(new ResourceKey( $"{effect.Drawing.MaterialName}_txtr", GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_TXTR)); - var material = MakeParticleMaterial(textureAsset.GetSelectedImageAsUnityTexture(ContentProvider.Get()), + var material = MakeParticleMaterial(textureAsset.GetSelectedImageAsUnityTexture(), effect.Drawing.ParticleDrawType); system.GetComponent().sharedMaterial = material; particleObject.GetComponent().AddReference(textureAsset); diff --git a/Assets/Scripts/OpenTS2/SimAntics/Primitives/VMLua.cs b/Assets/Scripts/OpenTS2/SimAntics/Primitives/VMLua.cs index c1432de7..195b5dde 100644 --- a/Assets/Scripts/OpenTS2/SimAntics/Primitives/VMLua.cs +++ b/Assets/Scripts/OpenTS2/SimAntics/Primitives/VMLua.cs @@ -4,7 +4,6 @@ using System.Text; using System.Threading.Tasks; using MoonSharp.Interpreter; -using OpenTS2.Client; using OpenTS2.Common; using OpenTS2.Content; using OpenTS2.Content.DBPF; @@ -55,14 +54,14 @@ public override VMReturnValue Execute(VMContext ctx) param2 = ctx.GetData(param2DataSource, param2DataValue); } - var luaStringSet = ContentProvider.Get().GetAsset(new ResourceKey(stringSetID, stringGroupID, TypeIDs.STR)); + var luaStringSet = ContentManager.Instance.GetAsset(new ResourceKey(stringSetID, stringGroupID, TypeIDs.STR)); var scriptName = luaStringSet.StringData.GetString(stringIndex, Languages.USEnglish); var scriptDesc = luaStringSet.StringData.GetDescription(stringIndex, Languages.USEnglish); var scriptSource = scriptDesc; - var luaManager = LuaManager.Get(); + var luaManager = LuaManager.Instance; if (useFile) { diff --git a/Assets/Scripts/OpenTS2/SimAntics/Primitives/VMPrimitiveRegistry.cs b/Assets/Scripts/OpenTS2/SimAntics/Primitives/VMPrimitiveRegistry.cs index 691ae17f..e250008f 100644 --- a/Assets/Scripts/OpenTS2/SimAntics/Primitives/VMPrimitiveRegistry.cs +++ b/Assets/Scripts/OpenTS2/SimAntics/Primitives/VMPrimitiveRegistry.cs @@ -8,7 +8,7 @@ namespace OpenTS2.SimAntics.Primitives { public static class VMPrimitiveRegistry { - private static Dictionary s_primitiveByOpCode = new Dictionary(); + private static Dictionary PrimitiveByOpCode = new Dictionary(); public static void Initialize() { @@ -23,7 +23,7 @@ public static void Initialize() public static void RegisterPrimitive(ushort opcode) where T : VMPrimitive { - s_primitiveByOpCode[opcode] = Activator.CreateInstance(typeof(T)) as VMPrimitive; + PrimitiveByOpCode[opcode] = Activator.CreateInstance(typeof(T)) as VMPrimitive; } public static T GetPrimitive(ushort opcode) where T : VMPrimitive @@ -33,7 +33,7 @@ public static T GetPrimitive(ushort opcode) where T : VMPrimitive public static VMPrimitive GetPrimitive(ushort opcode) { - if (s_primitiveByOpCode.TryGetValue(opcode, out VMPrimitive returnPrim)) + if (PrimitiveByOpCode.TryGetValue(opcode, out VMPrimitive returnPrim)) return returnPrim; return null; } diff --git a/Assets/Scripts/OpenTS2/SimAntics/VM.cs b/Assets/Scripts/OpenTS2/SimAntics/VM.cs index 780b7958..1cc03757 100644 --- a/Assets/Scripts/OpenTS2/SimAntics/VM.cs +++ b/Assets/Scripts/OpenTS2/SimAntics/VM.cs @@ -1,7 +1,7 @@ -using OpenTS2.Client; using OpenTS2.Common; using OpenTS2.Content; using OpenTS2.Files.Formats.DBPF; +using System; using System.Collections; using System.Collections.Generic; using System.Linq; @@ -18,6 +18,7 @@ public class VM public VMScheduler Scheduler = new VMScheduler(); public List Entities = new List(); public uint CurrentTick = 0; + public Action ExceptionHandler; private Dictionary _entitiesByID = new Dictionary(); @@ -49,13 +50,14 @@ public void SetGlobal(VMGlobals global, short value) void InitializeGlobalState() { - var epManager = EPManager.Get(); + var epManager = EPManager.Instance; var epFlags1 = (short)(epManager.InstalledProducts & 0xFFFF); var epFlags2 = (short)(epManager.InstalledProducts >> 16); SetGlobal(VMGlobals.GameEditionFlags1, epFlags1); SetGlobal(VMGlobals.GameEditionFlags2, epFlags2); - var settings = Settings.Get(); - SetGlobal(VMGlobals.CurrentLanguage, (short)settings.Language); + var globals = GameGlobals.Instance; + SetGlobal(VMGlobals.CurrentLanguage, (short)globals.Language); + SetGlobal(VMGlobals.Year, 1997); } /// @@ -66,7 +68,19 @@ public void Tick() Scheduler.OnBeginTick(this); foreach(var entity in Entities) { - entity.Tick(); + try + { + entity.Tick(); + } + catch(Exception e) + { + // If we don't have an exception handler just re-throw to avoid swallowing errors. + if (ExceptionHandler == null) + { + throw; + } + ExceptionHandler?.Invoke(e, entity); + } } Scheduler.OnEndTick(this); CurrentTick++; @@ -77,7 +91,7 @@ public void Tick() /// public static BHAVAsset GetBHAV(ushort id, uint groupID) { - return ContentProvider.Get().GetAsset(new ResourceKey(id, groupID, TypeIDs.BHAV)); + return ContentManager.Instance.GetAsset(new ResourceKey(id, groupID, TypeIDs.BHAV)); } public VMEntity GetEntityByID(short id) diff --git a/Assets/Scripts/OpenTS2/SimAntics/VMContext.cs b/Assets/Scripts/OpenTS2/SimAntics/VMContext.cs index 87afb5a9..16ae5252 100644 --- a/Assets/Scripts/OpenTS2/SimAntics/VMContext.cs +++ b/Assets/Scripts/OpenTS2/SimAntics/VMContext.cs @@ -27,6 +27,7 @@ public short GetData(VMDataSource source, short dataIndex) { VMDataSource.Globals => VM.GetGlobal((ushort)dataIndex), VMDataSource.MyObjectsAttributes => Entity.Attributes[dataIndex], + VMDataSource.MyObjectsSemiAttributes => Entity.SemiAttributes[dataIndex], VMDataSource.MyObject => Entity.ObjectData[dataIndex], VMDataSource.StackObject => StackObjectEntity.ObjectData[dataIndex], VMDataSource.Literal => dataIndex, @@ -38,10 +39,12 @@ public short GetData(VMDataSource source, short dataIndex) VMDataSource.Local => StackFrame.Locals[dataIndex], VMDataSource.StackObjectsDefinition => (short)StackObjectEntity.ObjectDefinition.Fields[dataIndex], VMDataSource.StackObjectsAttributes => StackObjectEntity.Attributes[dataIndex], + VMDataSource.StackObjectsSemiAttributes => StackObjectEntity.SemiAttributes[dataIndex], + VMDataSource.StackObjectsSemiAttributeByParam => StackObjectEntity.SemiAttributes[StackFrame.Arguments[dataIndex]], _ => throw new SimAnticsException($"Attempted to retrieve a variable from an out of range data source ({source}[{dataIndex}]).", StackFrame) }; } - catch (ArgumentOutOfRangeException) + catch (IndexOutOfRangeException) { throw new SimAnticsException($"Attempted to retrieve a variable from an out of range data index ({source}[{dataIndex}]).", StackFrame); } @@ -59,6 +62,9 @@ public void SetData(VMDataSource source, short dataIndex, short value) case VMDataSource.MyObjectsAttributes: Entity.Attributes[dataIndex] = value; return; + case VMDataSource.MyObjectsSemiAttributes: + Entity.SemiAttributes[dataIndex] = value; + return; case VMDataSource.MyObject: Entity.ObjectData[dataIndex] = value; return; @@ -86,10 +92,16 @@ public void SetData(VMDataSource source, short dataIndex, short value) case VMDataSource.StackObjectsAttributes: StackObjectEntity.Attributes[dataIndex] = value; return; + case VMDataSource.StackObjectsSemiAttributes: + StackObjectEntity.SemiAttributes[dataIndex] = value; + return; + case VMDataSource.StackObjectsSemiAttributeByParam: + StackObjectEntity.SemiAttributes[StackFrame.Arguments[dataIndex]] = value; + return; } throw new SimAnticsException($"Attempted to modify a variable from an out of range data source ({source}[{dataIndex}]).", StackFrame); } - catch (ArgumentOutOfRangeException) + catch (IndexOutOfRangeException) { throw new SimAnticsException($"Attempted to modify a variable from an out of range data index ({source}[{dataIndex}]).", StackFrame); } diff --git a/Assets/Scripts/OpenTS2/SimAntics/VMEntity.cs b/Assets/Scripts/OpenTS2/SimAntics/VMEntity.cs index 0396e98f..972910d7 100644 --- a/Assets/Scripts/OpenTS2/SimAntics/VMEntity.cs +++ b/Assets/Scripts/OpenTS2/SimAntics/VMEntity.cs @@ -1,7 +1,11 @@ -using OpenTS2.Content.DBPF; +using OpenTS2.Common; +using OpenTS2.Content; +using OpenTS2.Content.DBPF; using OpenTS2.Files.Formats.DBPF; +using OpenTS2.Lua.Disassembly.OpCodes; using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -21,6 +25,7 @@ public class VMEntity public VM VM; public ObjectDefinitionAsset ObjectDefinition; public short[] Attributes; + public short[] SemiAttributes; public short[] ObjectData = new short[114]; public uint PrivateGroupID => ObjectDefinition.GlobalTGI.GroupID; public uint SemiGlobalGroupID @@ -29,7 +34,7 @@ public uint SemiGlobalGroupID { var semiGlobal = ObjectDefinition.SemiGlobal; if (semiGlobal == null) - return 0; + throw new FileNotFoundException($"Object {ObjectDefinition.FileName} ({ObjectDefinition.GlobalTGI}) has no semi-global file"); return semiGlobal.SemiGlobalGroupID; } } @@ -42,7 +47,30 @@ protected VMEntity() public VMEntity(ObjectDefinitionAsset objectDefinition) : this() { ObjectDefinition = objectDefinition; - Attributes = new short[objectDefinition.NumAttributes]; + Attributes = new short[GetNumberOfAttributes()]; + SemiAttributes = new short[GetNumberOfSemiGlobalAttributes()]; + } + + // TODO: Verify these two methods below are right. Sometimes objdefs have 0 attributes but do have attribute labels and get/set their attributes. + private int GetNumberOfAttributes() + { + var objDefAttributes = ObjectDefinition.NumAttributes; + var attrLabels = ContentManager.Instance.GetAsset(new ResourceKey(0x100, PrivateGroupID, TypeIDs.STR)); + if (attrLabels == null) + return objDefAttributes; + var attrLabelsCount = attrLabels.StringData.Strings[Languages.USEnglish].Count; + return attrLabelsCount > objDefAttributes ? attrLabelsCount : objDefAttributes; + } + + private int GetNumberOfSemiGlobalAttributes() + { + var semiGlobal = ObjectDefinition.SemiGlobal; + if (semiGlobal == null) + return 0; + var semiAttributeLabels = ContentManager.Instance.GetAsset(new ResourceKey(0x100, semiGlobal.SemiGlobalGroupID, TypeIDs.STR)); + if (semiAttributeLabels == null) + return 0; + return semiAttributeLabels.StringData.Strings[Languages.USEnglish].Count; } public short GetObjectData(VMObjectData field) @@ -85,16 +113,25 @@ public void Delete() public BHAVAsset GetBHAV(ushort treeID) { // 0x0XXX is global scope, 0x1XXX is private scope and 0x2XXX is semiglobal scope. - var groupid = SemiGlobalGroupID; + uint groupid; if (treeID < 0x1000) groupid = GroupIDs.Global; else if (treeID < 0x2000) groupid = PrivateGroupID; + else + groupid = SemiGlobalGroupID; return VM.GetBHAV(treeID, groupid); } + public void PushTreeToThread(VMThread thread, ushort treeId) + { + var bhav = GetBHAV(treeId); + var stackFrame = new VMStackFrame(bhav, thread); + thread.Frames.Push(stackFrame); + } + public VMExitCode RunTreeImmediately(ushort treeID) { var thread = new VMThread(this); diff --git a/Assets/Scripts/OpenTS2/UI/CursorController.cs b/Assets/Scripts/OpenTS2/UI/CursorController.cs index b8dbf82f..75f1242c 100644 --- a/Assets/Scripts/OpenTS2/UI/CursorController.cs +++ b/Assets/Scripts/OpenTS2/UI/CursorController.cs @@ -9,8 +9,7 @@ namespace OpenTS2.UI { public class CursorController : MonoBehaviour { - public static CursorController Singleton => s_singleton; - static CursorController s_singleton = null; + public static CursorController Instance { get; private set; } public enum CursorType { @@ -46,7 +45,7 @@ public static CursorType Cursor /// Cursor path relative to TSData. private void RegisterCursorRelativePath(CursorType type, string filename) { - var absolutePath = Filesystem.GetLatestFilePath(Path.Combine("Res/UI/Cursors",filename)); + var absolutePath = Filesystem.GetLatestFilePath(Path.Combine("TSData/Res/UI/Cursors",filename)); if (absolutePath != null) RegisterCursorAbsolutePath(type, absolutePath); } @@ -66,13 +65,7 @@ private void RegisterCursorAbsolutePath(CursorType type, string filename) private void Awake() { - if (s_singleton != null) - { - Destroy(gameObject); - return; - } - s_singleton = this; - DontDestroyOnLoad(gameObject); + Instance = this; RegisterCursors(); } diff --git a/Assets/Scripts/OpenTS2/UI/Layouts/Lot.meta b/Assets/Scripts/OpenTS2/UI/Layouts/Lot.meta new file mode 100644 index 00000000..da027278 --- /dev/null +++ b/Assets/Scripts/OpenTS2/UI/Layouts/Lot.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 36c3b264b4416d742b336bab949d1995 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/UI/Layouts/Lot/LotViewBuildModeHUD.cs b/Assets/Scripts/OpenTS2/UI/Layouts/Lot/LotViewBuildModeHUD.cs new file mode 100644 index 00000000..aa14809b --- /dev/null +++ b/Assets/Scripts/OpenTS2/UI/Layouts/Lot/LotViewBuildModeHUD.cs @@ -0,0 +1,626 @@ +using OpenTS2.Common; +using OpenTS2.Content; +using OpenTS2.Content.DBPF; +using OpenTS2.Content.DBPF.Scenegraph; +using OpenTS2.Engine.Modes.Build; +using OpenTS2.Engine.Modes.Build.Tools; +using OpenTS2.Files.Formats.DBPF; +using OpenTS2.Files.Formats.XML; +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using UnityEngine.UI; + +namespace OpenTS2.UI.Layouts.Lot +{ + /// + /// This is a sub-control of the with functionality serving the Build Mode menus in the Lot View UI puck + /// + public class LotViewBuildModeHUD : UILayoutInstance + { + class BuildHUD_CatalogItemComponent : UILayoutInstance + { + //PRIVATE + const uint BaseID = 0xDAFE6503; + const uint PreviewID = 0x00000001; + private CatalogObjectAsset item; + public CatalogObjectAsset SelectedItem => item; + + Material displayMaterial; + + //PROTECTED + protected override ResourceKey UILayoutResourceKey => new ResourceKey(BaseID, 0xA99D8A11, TypeIDs.UI); + + //PUBLIC + public event EventHandler Clicked; + + public BuildHUD_CatalogItemComponent(Transform parent) : base(parent) + { + Init(); + } + + void Init() + { + Components[0].GetChildByID(0x03).OnClick += delegate + { + Clicked?.Invoke(this, SelectedItem); + }; + } + + /// + /// Changes this component's displayed texture and attached catalog asset + /// + /// + public void Display(CatalogObjectAsset Asset) + { + if(displayMaterial != null) + { + UnityEngine.Object.Destroy(displayMaterial); + displayMaterial = null; + } + + item = Asset; + + var content = ContentProvider.Get(); + var material = content.GetAsset( + new ResourceKey($"{Asset.Material}_txmt", GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_TXMT)); + + var preview = Components[0].GetChildByID(PreviewID); + preview.RectTransformComponent.localPosition = new Vector3(8, -8); + preview.RectTransformComponent.sizeDelta = new Vector2(34,34); + preview.gameObject.SetActive(true); + + //Set preview image + var bmp = preview.GetComponent(); + displayMaterial = material.GetAsUnityMaterial(); + bmp.texture = displayMaterial.mainTexture; + } + } + + /// + /// Contains the state of the catelog UI flyout + /// + class BuildHUD_CatalogComponent + { + const int XMARGIN = 10, YMARGIN = 5; // Margins between catalog items in the menu + internal const uint CatalogItemsExtender = 0xAD502BBF; + const uint CatalogItemsComponent = 0x00001006; + const uint PreviousButton = 0x00001004; + const uint NextButton = 0x00001005; + + UIComponent rootElement; + internal bool opened { get; private set; } + + private string subsort = "all"; + int itemsPerPage = 6, currentPage = 1; + + List items = new List(); + /// + /// The list of reusable UIComponent instances that will dynamically update their previews depending on which page we're on + /// + List controls = new List(); + + public BuildHUD_CatalogComponent(UIComponent CatalogComponent) + { + rootElement = CatalogComponent; + + Init(); + Close(); + } + + void Init() + { + var catalogItemsComponent = rootElement.GetChildByID(CatalogItemsComponent); + catalogItemsComponent.gameObject.SetActive(true); + catalogItemsComponent.GetComponent().enabled = false; // background is buggy turn it off + + for(int item = 0; item < itemsPerPage; item++) // create dynamic items + { + int x = item / 2; + int y = item - (x * 2); + + var control = new BuildHUD_CatalogItemComponent(catalogItemsComponent.transform); + var ctrlTransform = control.Components[0].RectTransformComponent; + ctrlTransform.localPosition = new Vector3( // handle padding here + (ctrlTransform.sizeDelta.x + XMARGIN) * x, -(ctrlTransform.sizeDelta.y + YMARGIN) * y); + controls.Add(control); + + //CLICK EVENT + control.Clicked += CatalogItemSelected; + } + + //Rig up next and prev buttons + var prevButton = rootElement.GetChildByID(PreviousButton); + prevButton.OnClick += Previous; + var nextButton = rootElement.GetChildByID(NextButton); + nextButton.OnClick += Advance; + } + + private void CatalogItemSelected(object sender, CatalogObjectAsset e) + { + //If the current build tool is compatible with patterns -- invoke it + (BuildModeServer.Get().CurrentTool as IPatternSelectableBuildTool)?.SetPaintPattern(e.Material); + } + + void Advance() => SwitchPage(currentPage + 1); + void Previous() => SwitchPage(currentPage - 1); + /// + /// Switches to the given page in the catalog by updating the dynamic controls to the new page's contents + /// + /// + void SwitchPage(int PageNumber) + { + void EnableButtons() + { + var button = rootElement.GetChildByID(PreviousButton); + button.gameObject.SetActive(true); + button = rootElement.GetChildByID(NextButton); + button.gameObject.SetActive(true); + } + void DisableForward() + { + var button = rootElement.GetChildByID(NextButton); + button.gameObject.SetActive(false); + } + void DisableBackward() + { + var button = rootElement.GetChildByID(PreviousButton); + button.gameObject.SetActive(false); + } + + EnableButtons(); // any buttons that are disabled should be re-enabled for safety. + + currentPage = PageNumber; + if (currentPage <= 0) + { + currentPage = 0; + DisableBackward(); // first page, disable back button + } + + int startIndex = currentPage * itemsPerPage; + + var itemsFilter = (IEnumerable)items; + if (subsort == "ots2_hiddentiles") + { + itemsFilter = items.Where(x => ((Uint32Prop)x.Properties.Properties["showincatalog"]).Value == 0); + } + else if (subsort != "all") // filter the itemssource if applicable (ignore this filter if "all" is selected) + itemsFilter = items.Where(x => ((StringProp)x.Properties.Properties["subsort"]).Value == subsort); + + for (int item = 0; item < itemsPerPage; item++) + { + //Set buttons hidden at first until some content to show has been found + var control = controls[item]; + control.Components[0].gameObject.SetActive(false); + + //attempt to load the content item + var assetRef = itemsFilter.ElementAtOrDefault(startIndex + item); + if (assetRef == null) continue; // no content here + //found some content, make the button visible and display a preview of the catalog item + control.Components[0].gameObject.SetActive(true); + control.Display(assetRef); + } + + if (startIndex + itemsPerPage >= itemsFilter.Count()) // end of last page + DisableForward(); // disable forward button + } + + public void Close() + { + rootElement.gameObject.SetActive(false); + opened = false; + } + public void Open(string CatelogItemType, string Subsort = "all") + { + if (string.IsNullOrWhiteSpace(Subsort)) + Subsort = "all"; + + rootElement.gameObject.SetActive(true); + opened = true; + + //Update the selection of items to match the definition + subsort = Subsort; + UpdateItemsSource(CatalogManager.Get().Objects.Where(x => x.Type == CatelogItemType)); + } + public void SetLocalPosition(Vector3 Position) => + rootElement.RectTransformComponent.localPosition = Position; + + /// + /// Updates the catalog control's items source property. + /// Use this when changing the selection of items being shown in the catelog. + /// You do not need to account for multiple pages of items, that will be handled automatically by the control. + /// + void UpdateItemsSource(IEnumerable CatalogItems) + { + items.Clear(); + items.AddRange(CatalogItems); + + SwitchPage(0); // switch to page one of the new data + } + + /// + /// Sets a filter on the ItemsSource. + /// See: and + /// + /// + /// + internal void SetSubsort(string Subsort) + { + subsort = Subsort; + SwitchPage(0); + } + } + + #region TopLevelHUDElements + + /// + /// Sorts (pages) for different tools in the build mode hud + /// + enum BuildHUD_Sorts : uint + { + TopLevel = 0x0000A000, + Walls = 0x0000B100, + Foundations = 0x0000B200, + DoorsWindowsArches = 0x0000B300, + Floors = 0x0000B400, + WallPaints = 0x0000B500, + Stairs = 0x0000B600, + Terrain = 0x0000B700, + GardenCenter = 0x0000B800, + Roofs = 0x0000B900, + Garages = 0x0000BB00, + Architecture = 0x0000BC00, + Misc = 0x0000BA00 + } + enum BuildHUD_CollectionPages : uint + { + Normal = 0x000000A8 + } + enum BuildHUD_BasicToolButtons : uint + { + Hand = 0x000000A5, + EyedropperTool = 0x000000A4 + } + + #endregion + + #region Subsorts + + enum BuildHUD_TopLevelButtons : uint + { + TopLevelSortButton = 0x000000A6, + WallsSortButton = 0x0000A100, + FoundationsSortButton = 0x0000A200, + DoorsAndWindowsSortButton = 0x0000A300, + FloorsSortButton = 0x0000A400, + WallPaintsSortButton = 0x0000A500, + StairsSortButton = 0x0000A600, + TerrainCenterButton = 0x0000A700, + GardenCenterButton = 0x0000A800, + RoofsSortButton = 0x0000A900, + MiscButton = 0x0000AA00, + GarageButton = 0x0000AB00, + ArchitectureSortButton = 0x0000AC00, + } + enum BuildHUD_WallsSortButtons : uint + { + WallsNRooms = 0x0000B120, + HalfWalls = 0x0000B130 + } + enum BuildHUD_TerrainSortButtons : uint + { + ElevationTools = 0x0000B720, + TerrainPaints = 0x0000B730, // called 'grass' in UI, pretty cool :0 + Water = 0x0000B740, + FlattenLot = 0x000000AD, + } + enum BuildHUD_TerrainBrushSizeButtons : uint + { + SmallSizeButton = 0x0000B751, + MedSizeButton = 0x0000B752, + LgSizeButton = 0x0000B753, + } + enum BuildHUD_FloorsSubsortButtons : uint + { + StoneButton = 0x0000B420, + BrickButton = 0x0000B430, + WoodButton = 0x0000B440, + CarpetButton = 0x0000B450, + TileButton = 0x0000B460, + LinoleumButton = 0x0000B470, + PouredButton = 0x0000B480, + OtherButton = 0x0000B490, + AllButton = 0x0000B4A0, + } + + #endregion + + const uint BaseID = 0x49060003; + const uint TileBG = 0xB4; // UI Background Panel + const uint EndCap = 0x000000B5; // UI Curvy End Cap + const uint ProdCatelogFlyout = 0x49063004; + const uint AutoRoofOptionsExtender = 0x000000AC; + const uint TerrainPageSizesGroup = 0x0000B750; + + protected override ResourceKey UILayoutResourceKey => new ResourceKey(BaseID, 0xA99D8A11, TypeIDs.UI); + UIComponent rootElement => Components[0]; + + //Pages (Sorts) + + /// + /// Contains information for each sort page in build mode to display it correctly + /// + class BuildHUDSort + { + /// + /// The enum type that has the IDs for the buttons that are inside of this sort that should be Toggled/Untoggled + /// after the sort is opened and dismissed + /// + public Type ButtonIDsEnum { get; set; } = null; + /// + /// The UI ID for this sort + /// + public uint SortGroupID { get; set; } + + //CATALOG PROVIDER + public string CatalogItemType { get; set; } + public bool HasCatalogItems => CatalogItemType != null; + public string CatalogDefaultSubsort { get; set; } = "all"; + + public BuildHUDSort(Type buttonIDsEnum, uint sortGroupID) + { + ButtonIDsEnum = buttonIDsEnum; + SortGroupID = sortGroupID; + } + } + + BuildHUDSort CurrentSort; + /// + /// Links Sort buttons to their corresponding pages in the interface + /// Wall Button links to the Wall Subpage with Half Walls, Regular Walls, Diagonal Room, etc. + /// + Dictionary sortPageMap = new Dictionary() + { + { BuildHUD_Sorts.TopLevel, new BuildHUDSort(typeof(BuildHUD_TopLevelButtons), (uint)BuildHUD_Sorts.TopLevel) }, + { BuildHUD_Sorts.Walls, new BuildHUDSort(typeof(BuildHUD_WallsSortButtons), (uint)BuildHUD_Sorts.Walls) }, + { BuildHUD_Sorts.Terrain, new BuildHUDSort(typeof(BuildHUD_TerrainSortButtons), (uint)BuildHUD_Sorts.Terrain) }, + { BuildHUD_Sorts.Floors, new BuildHUDSort(typeof(BuildHUD_FloorsSubsortButtons), (uint)BuildHUD_Sorts.Floors) + { // activate the catelog page for this sort + CatalogItemType = CatalogObjectType.Floor, + } + }, + }; + + // UI buttons and event system + Dictionary buildHUDButtonCallbacks; // built at runtime + /// + /// All UI buttons added to the event system (See: ) will set this value to + /// themselves prior to the event being called (May change later) + /// + UIButtonComponent CurrentButtonEventContext; + BuildHUD_CatalogComponent Catalog; + + public bool CatalogOpen => Catalog.opened; + + public LotViewBuildModeHUD() : this(MainCanvas) + { + + } + public LotViewBuildModeHUD(Transform Canvas) : base(Canvas) + { + Init(); + BuildUIEventsMap(); + WireUpUIEvents(); + } + + void Init() + { + //Position in bot left + var root = Components[0]; + root.SetAnchor(UIComponent.AnchorType.BottomLeft); + root.transform.position = new Vector3(105, root.transform.position.y, 0); + + //fix sizing + var iconButton = root.GetChildByID((uint)BuildHUD_BasicToolButtons.Hand); + iconButton.RectTransformComponent.sizeDelta = new Vector2(30, 30); + iconButton = root.GetChildByID((uint)BuildHUD_BasicToolButtons.EyedropperTool); + iconButton.RectTransformComponent.sizeDelta = new Vector2(30, 30); + + //turn off all controls except necessary ones + var autoRoofOptions = root.GetChildByID(AutoRoofOptionsExtender); + autoRoofOptions.gameObject.SetActive(false); + Catalog = new BuildHUD_CatalogComponent(root.GetChildByID(BuildHUD_CatalogComponent.CatalogItemsExtender)); + } + + void BuildUIEventsMap() + { + buildHUDButtonCallbacks = new Dictionary() + { + // BASIC BUTTONS + { (uint)BuildHUD_BasicToolButtons.Hand, delegate { ActionChangeTool(BuildTools.Hand); } }, + + // TOP LEVEL SORTS BUTTONS + { (uint)BuildHUD_TopLevelButtons.TopLevelSortButton, delegate { ActionChangeSort(BuildHUD_Sorts.TopLevel); } }, + { (uint)BuildHUD_TopLevelButtons.WallsSortButton, delegate { ActionChangeSort(BuildHUD_Sorts.Walls); } }, + { (uint)BuildHUD_TopLevelButtons.DoorsAndWindowsSortButton, delegate { ActionChangeSort(BuildHUD_Sorts.DoorsWindowsArches); } }, + { (uint)BuildHUD_TopLevelButtons.FloorsSortButton, delegate + { + ActionChangeSort(BuildHUD_Sorts.Floors); + ActionChangeTool(BuildTools.Floor); + } + }, + { (uint)BuildHUD_TopLevelButtons.WallPaintsSortButton, delegate { ActionChangeSort(BuildHUD_Sorts.WallPaints); } }, + { (uint)BuildHUD_TopLevelButtons.ArchitectureSortButton, delegate { ActionChangeSort(BuildHUD_Sorts.Architecture); } }, + { (uint)BuildHUD_TopLevelButtons.GardenCenterButton, delegate { ActionChangeSort(BuildHUD_Sorts.GardenCenter); } }, + { (uint)BuildHUD_TopLevelButtons.TerrainCenterButton, delegate { ActionChangeSort(BuildHUD_Sorts.Terrain); } }, + { (uint)BuildHUD_TopLevelButtons.GarageButton, delegate { ActionChangeSort(BuildHUD_Sorts.Garages); } }, + { (uint)BuildHUD_TopLevelButtons.MiscButton, delegate { ActionChangeSort(BuildHUD_Sorts.Misc); } }, + { (uint)BuildHUD_TopLevelButtons.RoofsSortButton, delegate { ActionChangeSort(BuildHUD_Sorts.Roofs); } }, + { (uint)BuildHUD_TopLevelButtons.FoundationsSortButton, delegate { + ActionChangeSort(BuildHUD_Sorts.Foundations); + ActionChangeTool(BuildTools.Foundation); + } + }, + { (uint)BuildHUD_TopLevelButtons.StairsSortButton, delegate { ActionChangeSort(BuildHUD_Sorts.Stairs); } }, + + // Walls N' Rooms + { (uint)BuildHUD_WallsSortButtons.WallsNRooms, delegate { ActionChangeTool(BuildTools.Wall); } }, + + // Terrain + { (uint)BuildHUD_TerrainSortButtons.ElevationTools, delegate { ActionSetTerrainBrushTool(BuildModeServer.TerrainModificationModes.Raise); } }, + { (uint)BuildHUD_TerrainSortButtons.Water, delegate { ActionSetTerrainBrushTool(BuildModeServer.TerrainModificationModes.Water); } }, + { (uint)BuildHUD_TerrainSortButtons.FlattenLot, delegate { BuildModeServer.Get().FlattenLot(); } }, + { (uint)BuildHUD_TerrainBrushSizeButtons.SmallSizeButton, delegate { ActionModifyTerrainBrushSize(0); } }, + { (uint)BuildHUD_TerrainBrushSizeButtons.MedSizeButton, delegate { ActionModifyTerrainBrushSize(TerrainBrushTool.TerrainBrushSizes.Medium); } }, + { (uint)BuildHUD_TerrainBrushSizeButtons.LgSizeButton, delegate { ActionModifyTerrainBrushSize(TerrainBrushTool.TerrainBrushSizes.Large); } }, + + //Floors + { (uint)BuildHUD_FloorsSubsortButtons.StoneButton, delegate { ActionInvokeSubSort("stone"); } }, + { (uint)BuildHUD_FloorsSubsortButtons.BrickButton, delegate { ActionInvokeSubSort("brick"); } }, + { (uint)BuildHUD_FloorsSubsortButtons.WoodButton, delegate { ActionInvokeSubSort("wood"); } }, + { (uint)BuildHUD_FloorsSubsortButtons.PouredButton, delegate { ActionInvokeSubSort("poured"); } }, + { (uint)BuildHUD_FloorsSubsortButtons.CarpetButton, delegate { ActionInvokeSubSort("carpet"); } }, + { (uint)BuildHUD_FloorsSubsortButtons.OtherButton, delegate { ActionInvokeSubSort("other"); } }, + { (uint)BuildHUD_FloorsSubsortButtons.AllButton, delegate { ActionInvokeSubSort("all"); } }, + { (uint)BuildHUD_FloorsSubsortButtons.TileButton, delegate { ActionInvokeSubSort("tile"); } }, + { (uint)BuildHUD_FloorsSubsortButtons.LinoleumButton, delegate { ActionInvokeSubSort("lino"); } }, + }; + } + + void WireUpUIEvents() + { + foreach(var keyValuePair in buildHUDButtonCallbacks) + { + uint compID = keyValuePair.Key; + var button = rootElement.GetChildByID(compID); + button.OnClick += delegate + { + //Set context + CurrentButtonEventContext = button; + //Invoke event + keyValuePair.Value(); + //Remove context + CurrentButtonEventContext = null; + }; + } + } + void EnsureGroupToggled(Type EnumTypeGroup, bool ToggleState = false) => EnsureGroup(EnumTypeGroup, (UIButtonComponent comp) => comp.SetToggled(ToggleState)); + void EnsureGroupHidden(Type EnumUIGroup) => EnsureGroup(EnumUIGroup, (UIComponent comp) => comp.gameObject.SetActive(false)); + void EnsureGroup(Type EnumUIGroup, Action Modification) => EnsureGroup(EnumUIGroup, Modification); + void EnsureGroup(Type EnumUIGroup, Action Modification) where T : UIComponent + { + if (EnumUIGroup == null) return; + foreach (uint groupID in Enum.GetValues(EnumUIGroup)) + Modification(rootElement.GetChildByID(groupID)); + } + void CloseCatalog() + { + Catalog.Close(); + //Set the endcap visible again + rootElement.GetChildByID(EndCap).gameObject.SetActive(true); + } + void OpenCatalog(string ObjectType, string Subsort = "all") + { + Catalog.Open(ObjectType, Subsort); + //Set the endcap invisible + rootElement.GetChildByID(EndCap).gameObject.SetActive(false); + } + + void ActionChangeTool(BuildTools Tool) + { + //Untoggle all basic buttons before transitioning + EnsureGroupToggled(typeof(BuildHUD_BasicToolButtons)); + if (CurrentSort != default) + EnsureGroupToggled(CurrentSort.ButtonIDsEnum); + //set tool button toggled + if (CurrentButtonEventContext != default) + CurrentButtonEventContext.SetToggled(true); + + BuildModeServer.Get().ChangeTool(Tool); + } + /// + /// Updates the User Interface to show the selected sort + /// See: to change the Subsort for this Sort + /// Note: This will cause whatever tool is currently being used to be cancelled. + /// + /// + void ActionChangeSort(BuildHUD_Sorts SortPage) + { + ActionChangeTool(BuildTools.None); // drop current tool + + //Hide all other pages before transitioning + EnsureGroupHidden(typeof(BuildHUD_Sorts)); + CloseCatalog(); + + var sortRoot = rootElement.GetChildByID((uint)SortPage); + sortRoot.gameObject.SetActive(true); + // stretch the ui panel to accomodate for the page we just opened up + float desiredWidth = sortRoot.RectTransformComponent.sizeDelta.x; + var TileBGComponent = rootElement.GetChildByID(TileBG).RectTransformComponent; // UI background panel + TileBGComponent.sizeDelta = new Vector2(desiredWidth, TileBGComponent.sizeDelta.y); + //move the endcap over so there's no gaps + var EndCapComp = rootElement.GetChildByID(EndCap).RectTransformComponent; // UI background panel + EndCapComp.localPosition = TileBGComponent.localPosition + new Vector3(desiredWidth, 0, 0); + //move the catelog as well -- whether it is active or not + Catalog.SetLocalPosition(new Vector3(TileBGComponent.localPosition.x + desiredWidth, 0, 0)); + //catelogComp.sizeDelta = new Vector2(catelogComp.position.x - (MainCanvas.transform as RectTransform).sizeDelta.x - 10, + // catelogComp.sizeDelta.y); + + if (sortPageMap.TryGetValue(SortPage, out var map)) + CurrentSort = map; + //Untoggle all buttons in the destination sort as well + EnsureGroupToggled(CurrentSort.ButtonIDsEnum); + + //open the catelog (if applicable) + if (CurrentSort.HasCatalogItems) + OpenCatalog(CurrentSort.CatalogItemType, CurrentSort.CatalogDefaultSubsort); + } + + /// + /// Sorts such as Flooring have subsorts (carpet, stone, etc.), this function will update the + /// subsort for the + /// + /// + void ActionInvokeSubSort(string Subsort) + { + EnsureGroupToggled(CurrentSort.ButtonIDsEnum); + if (Subsort == "all" && Input.GetKey(KeyCode.LeftShift)) // BuildDEBUG + Subsort = "ots2_hiddentiles"; + Catalog.SetSubsort(Subsort); + CurrentButtonEventContext.SetToggled(true); + } + /// + /// Invokes the Terrain brush tool and sets the size to Small by default + /// + /// + void ActionSetTerrainBrushTool(BuildModeServer.TerrainModificationModes BrushMode) + { + ActionChangeTool(BuildTools.TerrainBrush); + (BuildModeServer.Get().CurrentTool as TerrainBrushTool).CurrentBrushMode = BrushMode; + ActionModifyTerrainBrushSize(TerrainBrushTool.TerrainBrushSizes.Small); + } + /// + /// Updates the User Interface and the Terrain tool to match the selected size + /// + /// + void ActionModifyTerrainBrushSize(TerrainBrushTool.TerrainBrushSizes Size) + { + EnsureGroupToggled(typeof(BuildHUD_TerrainBrushSizeButtons)); + UIButtonComponent button = rootElement.GetChildByID((uint)BuildHUD_TerrainBrushSizeButtons.SmallSizeButton); + switch (Size) + { + case TerrainBrushTool.TerrainBrushSizes.Medium: // med + button = rootElement.GetChildByID((uint)BuildHUD_TerrainBrushSizeButtons.MedSizeButton); + break; + case TerrainBrushTool.TerrainBrushSizes.Large: // lg + button = rootElement.GetChildByID((uint)BuildHUD_TerrainBrushSizeButtons.LgSizeButton); + break; + default: + Size = TerrainBrushTool.TerrainBrushSizes.Small; break; + } + button.SetToggled(true); + (BuildModeServer.Get().CurrentTool as TerrainBrushTool).BrushSize = (int)Size; + } + } +} diff --git a/Assets/Scripts/OpenTS2/UI/Layouts/Lot/LotViewBuildModeHUD.cs.meta b/Assets/Scripts/OpenTS2/UI/Layouts/Lot/LotViewBuildModeHUD.cs.meta new file mode 100644 index 00000000..7615775c --- /dev/null +++ b/Assets/Scripts/OpenTS2/UI/Layouts/Lot/LotViewBuildModeHUD.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 81a357d2aeaa898479699bb2890f9123 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/UI/Layouts/Lot/LotViewHUD.cs b/Assets/Scripts/OpenTS2/UI/Layouts/Lot/LotViewHUD.cs new file mode 100644 index 00000000..29b0337a --- /dev/null +++ b/Assets/Scripts/OpenTS2/UI/Layouts/Lot/LotViewHUD.cs @@ -0,0 +1,182 @@ +using OpenTS2.Common; +using OpenTS2.Engine.Modes.Build; +using OpenTS2.Files.Formats.DBPF; +using OpenTS2.Scenes.Lot.State; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace OpenTS2.UI.Layouts +{ + + /// + /// The HUD found when the user is playing in a lot + /// + public class LotViewHUD : UILayoutInstance + { + //CONSTANTS + public enum HUD_UILotModes + { + None, + Live, + Buy, + Build, + Memories, + Settings + } + + const uint WallViewSelectorGadgetID = 0x00004000; + /// + /// probably not necessary since it's the only control in this UIData but im gonna roll w it + /// + const uint LotViewPuckID = 0xF15C6B85; + //Wall View button that invokes the Wall View Selector has 4 states for each wall view mode + const uint FoldButton_WallsDown = 0x00001100, FoldButton_WallsCutaway = 0x00001101, + FoldButton_WallsUp = 0x00001102, FoldButton_Roof = 0x00001103; + //Buttons inside the Wall View selector that change the Wall View Mode + const uint Button_WallsDown = 0x00000001, Button_WallsCutaway = 0x00000002, + Button_WallsUp = 0x00000003, Button_WallsRoof = 0x00000004; + const uint BuildButton = 0x77D97B28, BuyButton = 0x67D97B2A, LiveButton = 0x37D97B25, SettingsButton = 0x67D97B2F; + const uint FloorUpButton = 0x00002001, FloorDownButton = 0x00002000; + + //PRIVATE + UIComponent WallsUpDownSelector; + UIComponent rootElement => Components[0]; + + HUD_UILotModes CurrentMode = HUD_UILotModes.None; + + //EVENTS + public class ModeChangeEventArgs + { + public bool Allow = false; + HUD_UILotModes RequestedMode; + + public ModeChangeEventArgs(HUD_UILotModes requestedMode) + { + RequestedMode = requestedMode; + } + } + public event EventHandler OnModeChangeRequested; + public event EventHandler OnModeChanged; + + protected override ResourceKey UILayoutResourceKey => new ResourceKey(0x4905F85B, 0xA99D8A11, TypeIDs.UI); + public LotViewHUD() : this(MainCanvas) + { + + } + public LotViewHUD(Transform Canvas) : base(Canvas) + { + Init(); + WireUpUIEvents(); + } + + void Toggle(UIComponent comp) => comp.transform.gameObject.SetActive(!comp.transform.gameObject.activeSelf); + + /// + /// Sets the hud elements to default settings for first run + /// + void Init() + { + var root = Components[0]; + root.SetAnchor(UIComponent.AnchorType.Stretch); + var puck = root.GetChildByID(LotViewPuckID); + puck.SetAnchor(UIComponent.AnchorType.BottomLeft); // set gizmo to botleft + puck.transform.position = new Vector3(0, 200, 0); + + WallsUpDownSelector = root.GetChildByID(WallViewSelectorGadgetID, false); + Toggle(WallsUpDownSelector); + } + + /// + /// Sets up all button click event messages + /// + void WireUpUIEvents() + { + void RigUpSequential(uint Base, int count, Action Callback) + { + if (count < 0) return; // :| + if (Base + count > uint.MaxValue) throw new Exception($"UI Element ID overflow in WireUpUIEvents RigUpSeq method! {Base} + {count}"); + for (int i = 0; i < count; i++) + { + var button = rootElement.GetChildByID((uint)(Base + i)); // downcast doesn't matter per above + button.OnClick += Callback; + } + } + //Rig up Wall View Mode tray thing + RigUpSequential(FoldButton_WallsDown, 4, ShowHideWallViewOptions); + var modeButton = rootElement.GetChildByID(BuildButton); + modeButton.OnClick += delegate { SetMode(HUD_UILotModes.Build); }; // build mode button clicked + + //Wall view modes buttons + var wallButton = rootElement.GetChildByID(Button_WallsDown); + wallButton.OnClick += delegate { SetWallsCutawayMode(WallsMode.Down); }; + wallButton = rootElement.GetChildByID(Button_WallsCutaway); + wallButton.OnClick += delegate { SetWallsCutawayMode(WallsMode.Cutaway); }; + wallButton = rootElement.GetChildByID(Button_WallsUp); + wallButton.OnClick += delegate { SetWallsCutawayMode(WallsMode.Up); }; + wallButton = rootElement.GetChildByID(Button_WallsRoof); + wallButton.OnClick += delegate { SetWallsCutawayMode(WallsMode.Roof); }; + + //floor buttons + var floorButton = rootElement.GetChildByID(FloorUpButton); + floorButton.OnClick += delegate { SetFloorLevel(1); }; + floorButton = rootElement.GetChildByID(FloorDownButton); + floorButton.OnClick += delegate { SetFloorLevel(-1); }; + } + + void ShowHideWallViewOptions() + { + Toggle(WallsUpDownSelector); + } + + void SetWallsCutawayMode(WallsMode Mode) + { + var server = BuildModeServer.Get(); + var state = server.WorldState; + server.WorldState = new WorldState(state.Level, Mode); + server.InvalidateLotState(); + ShowHideWallViewOptions(); + } + + void SetFloorLevel(int Change) + { + var server = BuildModeServer.Get(); + var state = server.WorldState; + int level = Math.Max(0,state.Level + Change); // TODO: Make this base floor value... + server.WorldState = new WorldState(level, state.Walls); + server.InvalidateLotState(); + } + + /// + /// Sets the mode shown in the HUD + /// Note: If there are no subscribers to , the mode change will always be successful without verification. + /// + /// + public void SetMode(HUD_UILotModes Mode) + { + if (OnModeChangeRequested != null) + { + var args = new ModeChangeEventArgs(Mode); + OnModeChangeRequested(this, args); + if (!args.Allow) return; + } + //Change allowed + + CurrentMode = Mode; + var buildModeButton = rootElement.GetChildByID(BuildButton); + buildModeButton.SetToggled(false); + + switch(Mode) + { + case HUD_UILotModes.Build: + buildModeButton.SetToggled(true); + break; + } + + OnModeChanged?.Invoke(this, Mode); + } + } +} diff --git a/Assets/Scripts/OpenTS2/UI/Layouts/Lot/LotViewHUD.cs.meta b/Assets/Scripts/OpenTS2/UI/Layouts/Lot/LotViewHUD.cs.meta new file mode 100644 index 00000000..b9dc79d2 --- /dev/null +++ b/Assets/Scripts/OpenTS2/UI/Layouts/Lot/LotViewHUD.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5b5d074308e95ce42b13b0c46dd9eaed +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/UI/Layouts/Lot/LotViewHUDController.cs b/Assets/Scripts/OpenTS2/UI/Layouts/Lot/LotViewHUDController.cs new file mode 100644 index 00000000..278e11aa --- /dev/null +++ b/Assets/Scripts/OpenTS2/UI/Layouts/Lot/LotViewHUDController.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace OpenTS2.UI.Layouts.Lot +{ + public class LotViewHUDController : MonoBehaviour + { + //UI Parts + public LotViewBuildModeHUD BuildModePanel { get; private set; } + public LotViewHUD Puck { get; private set; } + + void Start() + { + BuildModePanel = new LotViewBuildModeHUD(); + Puck = new LotViewHUD(); + Puck.OnModeChanged += GizmoModeChanged; + } + + private void GizmoModeChanged(object sender, LotViewHUD.HUD_UILotModes e) + { + //TODO: Make UI react to mode changes ... for now not really necessary + } + + void Update() + { + + } + } +} diff --git a/Assets/Scripts/OpenTS2/UI/Layouts/Lot/LotViewHUDController.cs.meta b/Assets/Scripts/OpenTS2/UI/Layouts/Lot/LotViewHUDController.cs.meta new file mode 100644 index 00000000..22f6b2f3 --- /dev/null +++ b/Assets/Scripts/OpenTS2/UI/Layouts/Lot/LotViewHUDController.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9727801f799a10a41875182ace337639 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/UI/Layouts/MainMenu.cs b/Assets/Scripts/OpenTS2/UI/Layouts/MainMenu.cs index f73f68ee..59231f0a 100644 --- a/Assets/Scripts/OpenTS2/UI/Layouts/MainMenu.cs +++ b/Assets/Scripts/OpenTS2/UI/Layouts/MainMenu.cs @@ -130,7 +130,7 @@ public MainMenu(Transform canvas, bool fromNeighborhood = false) : base(canvas) } } - var contentProvider = ContentProvider.Get(); + var contentManager = ContentManager.Instance; // Assign random images to the Sims. var keyAmount = Mathf.Min(upperLeftKeys.Count, lowerRightKeys.Count); @@ -139,8 +139,8 @@ public MainMenu(Transform canvas, bool fromNeighborhood = false) : base(canvas) var upperLeftKey = upperLeftKeys[simTextureIndex]; var lowerRightKey = lowerRightKeys[simTextureIndex]; - upperLeftSim.SetTexture(contentProvider.GetAsset(upperLeftKey)); - lowerRightSim.SetTexture(contentProvider.GetAsset(lowerRightKey)); + upperLeftSim.SetTexture(contentManager.GetAsset(upperLeftKey)); + lowerRightSim.SetTexture(contentManager.GetAsset(lowerRightKey)); upperLeftSim.Color = Color.white; lowerRightSim.Color = Color.white; } @@ -151,7 +151,7 @@ public MainMenu(Transform canvas, bool fromNeighborhood = false) : base(canvas) // Unparent shade and move it to the top, so that it covers the main menu fully. _shade = Components[0].GetChildByID(ShadeID); - _shade.transform.parent = MainCanvas; + _shade.transform.SetParent(MainCanvas, false); _shade.transform.SetAsLastSibling(); _shade.SetAnchor(UIComponent.AnchorType.Center); @@ -182,7 +182,7 @@ bool ShouldNeighborhoodDisplayInChooser(Neighborhood neighborhood) // Set up the neighborhood icon grid and controls. void CreateNeighborhoodIcons() { - _neighborHoods = NeighborhoodManager.Neighborhoods.Where(ShouldNeighborhoodDisplayInChooser).ToList(); + _neighborHoods = NeighborhoodManager.Instance.Neighborhoods.Where(ShouldNeighborhoodDisplayInChooser).ToList(); var thumbsRectangle = Components[0].GetChildByID(ThumbsRectangleID); var thumbsCenter = thumbsRectangle.GetCenter(); @@ -224,7 +224,7 @@ void OnNeighborhoodIconClick(Neighborhood neighborhood) void OnQuit() { - ContentProvider.Get().Changes.SaveChanges(); + ContentManager.Instance.Changes.SaveChanges(); Application.Quit(); } diff --git a/Assets/Scripts/OpenTS2/UI/Layouts/NeighborhoodHUD.cs b/Assets/Scripts/OpenTS2/UI/Layouts/NeighborhoodHUD.cs index b1b7f0e6..9339ed2a 100644 --- a/Assets/Scripts/OpenTS2/UI/Layouts/NeighborhoodHUD.cs +++ b/Assets/Scripts/OpenTS2/UI/Layouts/NeighborhoodHUD.cs @@ -42,7 +42,7 @@ public NeighborhoodHUD(Transform canvas) : base(canvas) mainMenu.OnClick += OnMainMenu; var largeCityName = primaryOptions.GetChildByID(LargeCityNameTextID); - largeCityName.Text = NeighborhoodManager.CurrentNeighborhood.GetLocalizedName(); + largeCityName.Text = NeighborhoodManager.Instance.CurrentNeighborhood.GetLocalizedName(); } void OnMainMenu() diff --git a/Assets/Scripts/OpenTS2/UI/Layouts/NeighborhoodPreview.cs b/Assets/Scripts/OpenTS2/UI/Layouts/NeighborhoodPreview.cs index 52528f76..7ab10e9d 100644 --- a/Assets/Scripts/OpenTS2/UI/Layouts/NeighborhoodPreview.cs +++ b/Assets/Scripts/OpenTS2/UI/Layouts/NeighborhoodPreview.cs @@ -68,13 +68,13 @@ void Play() { if (_neighborhood == null) return; - if (NeighborhoodManager.CurrentNeighborhood == _neighborhood) + if (NeighborhoodManager.Instance.CurrentNeighborhood == _neighborhood) { Hide(); OnTryEnterActiveNeighborhood?.Invoke(); return; } - NeighborhoodManager.EnterNeighborhood(_neighborhood); + NeighborhoodManager.Instance.EnterNeighborhood(_neighborhood); } public void Hide() diff --git a/Assets/Scripts/OpenTS2/UI/Layouts/UILayoutInstance.cs b/Assets/Scripts/OpenTS2/UI/Layouts/UILayoutInstance.cs index 4b839f46..c381f020 100644 --- a/Assets/Scripts/OpenTS2/UI/Layouts/UILayoutInstance.cs +++ b/Assets/Scripts/OpenTS2/UI/Layouts/UILayoutInstance.cs @@ -19,8 +19,8 @@ public abstract class UILayoutInstance protected abstract ResourceKey UILayoutResourceKey { get; } public UILayoutInstance(Transform parent) { - var contentProvider = ContentProvider.Get(); - var layout = contentProvider.GetAsset(UILayoutResourceKey); + var contentManager = ContentManager.Instance; + var layout = contentManager.GetAsset(UILayoutResourceKey); Components = layout.Instantiate(parent); } } diff --git a/Assets/Scripts/OpenTS2/UI/ReiaPlayer.cs b/Assets/Scripts/OpenTS2/UI/ReiaPlayer.cs index a76d80e5..7d8ecadf 100644 --- a/Assets/Scripts/OpenTS2/UI/ReiaPlayer.cs +++ b/Assets/Scripts/OpenTS2/UI/ReiaPlayer.cs @@ -41,8 +41,8 @@ public void SetReia(Stream stream, bool streamed) public void SetReia(ResourceKey key, bool stream) { - var contentProvider = ContentProvider.Get(); - var bytes = contentProvider.GetEntry(key).GetBytes(); + var contentManager = ContentManager.Instance; + var bytes = contentManager.GetEntry(key).GetBytes(); var memStream = new MemoryStream(bytes); SetReia(memStream, stream); } diff --git a/Assets/Scripts/OpenTS2/UI/TextFieldBehaviour.cs b/Assets/Scripts/OpenTS2/UI/TextFieldBehaviour.cs index cf91b496..22e28e7c 100644 --- a/Assets/Scripts/OpenTS2/UI/TextFieldBehaviour.cs +++ b/Assets/Scripts/OpenTS2/UI/TextFieldBehaviour.cs @@ -17,7 +17,6 @@ namespace OpenTS2.UI public class TextFieldBehaviour : MonoBehaviour, ISelectHandler { private InputField inputField; - private bool isCaretPositionReset = false; void Start() { diff --git a/Assets/Scripts/OpenTS2/UI/UIBMPElement.cs b/Assets/Scripts/OpenTS2/UI/UIBMPElement.cs index 7feaedef..498946eb 100644 --- a/Assets/Scripts/OpenTS2/UI/UIBMPElement.cs +++ b/Assets/Scripts/OpenTS2/UI/UIBMPElement.cs @@ -32,8 +32,8 @@ public override void ParseProperties(UIProperties properties) public override UIComponent Instantiate(Transform parent) { var uiComponent = base.Instantiate(parent) as UIBMPComponent; - var contentProvider = ContentProvider.Get(); - var imageAsset = contentProvider.GetAsset(Image); + var contentManager = ContentManager.Instance; + var imageAsset = contentManager.GetAsset(Image); var rawImage = uiComponent.gameObject.AddComponent(); if (IgnoreMouse) rawImage.raycastTarget = false; diff --git a/Assets/Scripts/OpenTS2/UI/UIButtonComponent.cs b/Assets/Scripts/OpenTS2/UI/UIButtonComponent.cs index 1afe15ec..714d4f8e 100644 --- a/Assets/Scripts/OpenTS2/UI/UIButtonComponent.cs +++ b/Assets/Scripts/OpenTS2/UI/UIButtonComponent.cs @@ -8,18 +8,23 @@ using UnityEngine.UI; using UnityEngine.EventSystems; using OpenTS2.Content.DBPF; +using OpenTS2.Common; +using OpenTS2.Content; +using OpenTS2.Audio; namespace OpenTS2.UI { public class UIButtonComponent : UIComponent, IPointerEnterHandler, IPointerExitHandler, IPointerDownHandler, IPointerUpHandler { /// - /// Triggers when this button is clicked. Boolean argument specifies whether it was a double click. + /// Triggers when this button is clicked. /// public Action OnClick; public bool GreyedOut = false; + public ResourceKey ClickSound; private bool _hovering = false; private bool _held = false; + private bool _toggled = false; // some buttons are toggle buttons -- adding this here to account for this scenario private TextureAsset[] _textures; public RawImage RawImageComponent => GetComponent(); public void SetTexture(TextureAsset texture) @@ -48,6 +53,11 @@ void UpdateTexture() RawImageComponent.texture = _textures[0].Texture; else { + if (_toggled) // Toggle Button texture here + { + RawImageComponent.texture = _textures[2].Texture; + return; + } RawImageComponent.texture = _textures[1].Texture; if (_hovering && !UIManager.AnyMouseButtonHeld) RawImageComponent.texture = _textures[3].Texture; @@ -83,6 +93,7 @@ public void OnPointerDown(PointerEventData eventData) { if (eventData.button != PointerEventData.InputButton.Left && eventData.button != PointerEventData.InputButton.Right) return; + AudioManager.Instance.PlayUISound(ClickSound); _held = true; } @@ -91,9 +102,7 @@ public void OnPointerUp(PointerEventData eventData) if (eventData.button != PointerEventData.InputButton.Left && eventData.button != PointerEventData.InputButton.Right) return; if (_held && _hovering) - { - Click(); - } + OnClick?.Invoke(); _held = false; } @@ -101,5 +110,11 @@ void Click() { OnClick?.Invoke(); } + + public void SetToggled(bool Toggled) + { + _toggled = Toggled; + UpdateTexture(); + } } } diff --git a/Assets/Scripts/OpenTS2/UI/UIButtonElement.cs b/Assets/Scripts/OpenTS2/UI/UIButtonElement.cs index c5174c0f..fbf9e1ca 100644 --- a/Assets/Scripts/OpenTS2/UI/UIButtonElement.cs +++ b/Assets/Scripts/OpenTS2/UI/UIButtonElement.cs @@ -17,11 +17,13 @@ namespace OpenTS2.UI public class UIButtonElement : UIElement { public ResourceKey Image = default; + public ResourceKey ClickSound = default; protected override Type UIComponentType => typeof(UIButtonComponent); public override void ParseProperties(UIProperties properties) { base.ParseProperties(properties); Image = properties.GetImageKeyProperty("image"); + ClickSound = properties.GetSoundProperty("btnclicksnd"); } public override UIComponent Instantiate(Transform parent) { @@ -29,10 +31,11 @@ public override UIComponent Instantiate(Transform parent) var rawImage = uiComponent.gameObject.AddComponent(); if (IgnoreMouse) rawImage.raycastTarget = false; - var contentProvider = ContentProvider.Get(); - var imageAsset = contentProvider.GetAsset(Image); + var contentManager = ContentManager.Instance; + var imageAsset = contentManager.GetAsset(Image); if (imageAsset != null) uiComponent.SetTexture(imageAsset); + uiComponent.ClickSound = ClickSound; return uiComponent; } } diff --git a/Assets/Scripts/OpenTS2/UI/UIProperties.cs b/Assets/Scripts/OpenTS2/UI/UIProperties.cs index 92f69179..c3eab031 100644 --- a/Assets/Scripts/OpenTS2/UI/UIProperties.cs +++ b/Assets/Scripts/OpenTS2/UI/UIProperties.cs @@ -1,4 +1,5 @@ -using OpenTS2.Common; +using OpenTS2.Audio; +using OpenTS2.Common; using OpenTS2.Content; using OpenTS2.Content.DBPF; using OpenTS2.Files.Formats.DBPF; @@ -27,8 +28,8 @@ public StringReference(ResourceKey stringSet, int stringId) } public string GetLocalizedString() { - var contentProvider = ContentProvider.Get(); - var stringSet = contentProvider.GetAsset(StringSet); + var contentManager = ContentManager.Instance; + var stringSet = contentManager.GetAsset(StringSet); if (stringSet == null) return ""; return stringSet.GetString(StringID); @@ -96,6 +97,14 @@ public List GetStringListProperty(string property) return list; } + public ResourceKey GetSoundProperty(string property) + { + var hexList = GetHexListProperty(property); + if (hexList.Count < 2) + return default; + return AudioManager.Instance.GetAudioResourceKeyByInstanceID(hexList[1]); + } + public List GetHexListProperty(string property) { var list = new List(); diff --git a/Assets/Scripts/OpenTS2/UI/UITextElement.cs b/Assets/Scripts/OpenTS2/UI/UITextElement.cs index 6f4d093f..4bcc3dd1 100644 --- a/Assets/Scripts/OpenTS2/UI/UITextElement.cs +++ b/Assets/Scripts/OpenTS2/UI/UITextElement.cs @@ -15,6 +15,7 @@ namespace OpenTS2.UI public class UITextElement : UIElement { protected override Type UIComponentType => typeof(UITextComponent); + // TODO Default should be upper left, but looks ugly atm without fonts. public TextAnchor Alignment = TextAnchor.MiddleCenter; public Color32 ForeColor = Color.black; diff --git a/Assets/Shaders/Lot/Billboard.shader b/Assets/Shaders/Lot/Billboard.shader new file mode 100644 index 00000000..a100701b --- /dev/null +++ b/Assets/Shaders/Lot/Billboard.shader @@ -0,0 +1,69 @@ +Shader "Unlit/Billboard" +{ + Properties + { + _MainTex ("Texture", 2D) = "white" {} + } + SubShader + { + Tags{ "Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent" "DisableBatching" = "True" } + + ZWrite Off + Blend SrcAlpha OneMinusSrcAlpha + + Pass + { + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + // make fog work + #pragma multi_compile_fog + + #include "UnityCG.cginc" + + struct appdata + { + float4 vertex : POSITION; + float2 uv : TEXCOORD0; + }; + + struct v2f + { + float2 uv : TEXCOORD0; + UNITY_FOG_COORDS(1) + float4 pos : SV_POSITION; + }; + + sampler2D _MainTex; + float4 _MainTex_ST; + + v2f vert (appdata v) + { + v2f o; + o.pos = UnityObjectToClipPos(v.vertex); + o.uv = v.uv.xy; + + // billboard mesh towards camera + float3 vpos = mul((float3x3)unity_ObjectToWorld, v.vertex.xyz); + float4 worldCoord = float4(unity_ObjectToWorld._m03, unity_ObjectToWorld._m13, unity_ObjectToWorld._m23, 1); + float4 viewPos = mul(UNITY_MATRIX_V, worldCoord) + float4(vpos, 0); + float4 outPos = mul(UNITY_MATRIX_P, viewPos); + + o.pos = outPos; + + UNITY_TRANSFER_FOG(o,o.vertex); + return o; + } + + fixed4 frag (v2f i) : SV_Target + { + // sample the texture + fixed4 col = tex2D(_MainTex, i.uv); + // apply fog + UNITY_APPLY_FOG(i.fogCoord, col); + return col; + } + ENDCG + } + } +} diff --git a/Assets/Shaders/Lot/Billboard.shader.meta b/Assets/Shaders/Lot/Billboard.shader.meta new file mode 100644 index 00000000..775a27a2 --- /dev/null +++ b/Assets/Shaders/Lot/Billboard.shader.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 9027c75630615624b8d7e4b02852aa4e +ShaderImporter: + externalObjects: {} + defaultTextures: [] + nonModifiableTextures: [] + preprocessorOverride: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Shaders/Neighborhood/BakedDecal.shader b/Assets/Shaders/Neighborhood/BakedDecal.shader new file mode 100644 index 00000000..96030c0e --- /dev/null +++ b/Assets/Shaders/Neighborhood/BakedDecal.shader @@ -0,0 +1,62 @@ +// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)' + +Shader "OpenTS2/BakedDecal" +{ + Properties + { + _MainTex ("Texture", 2D) = "white" {} + } + SubShader + { + Tags { "RenderType" = "Transparent" "Queue" = "Transparent-2" } + LOD 100 + + Pass + { + ZWrite Off + Offset -1, -1 + Blend SrcAlpha OneMinusSrcAlpha + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + // make fog work + #pragma multi_compile_fog + + #include "UnityCG.cginc" + + struct appdata + { + float4 vertex : POSITION; + float2 uv : TEXCOORD0; + }; + + struct v2f + { + float4 vertex : SV_POSITION; + float2 uv : TEXCOORD0; + }; + + sampler2D _MainTex; + float4 _MainTex_ST; + + v2f vert (appdata v) + { + v2f o; + o.uv = v.uv; + o.vertex = UnityObjectToClipPos(v.vertex); + return o; + } + + fixed4 frag(v2f i) : SV_Target + { + + if (i.uv.x < 0 || i.uv.y < 0 || i.uv.x > 1 || i.uv.y > 1) + clip(-1); + // sample the texture + fixed4 col = tex2D(_MainTex, i.uv); + return col; + } + ENDCG + } + } +} diff --git a/Assets/Shaders/Neighborhood/BakedDecal.shader.meta b/Assets/Shaders/Neighborhood/BakedDecal.shader.meta new file mode 100644 index 00000000..8ed5c09d --- /dev/null +++ b/Assets/Shaders/Neighborhood/BakedDecal.shader.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: cd1c2fe69305d6340a8e116e63955e26 +ShaderImporter: + externalObjects: {} + defaultTextures: [] + nonModifiableTextures: [] + preprocessorOverride: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Tests/OpenTS2/Content/ContentManagerTest.cs b/Assets/Tests/OpenTS2/Content/ContentManagerTest.cs new file mode 100644 index 00000000..1eb4d6a8 --- /dev/null +++ b/Assets/Tests/OpenTS2/Content/ContentManagerTest.cs @@ -0,0 +1,52 @@ +using NUnit.Framework; +using OpenTS2.Common; +using OpenTS2.Content; +using OpenTS2.Content.DBPF; +using OpenTS2.Engine; +using OpenTS2.Files; +using OpenTS2.Files.Formats.DBPF; + +public class ContentManagerTest +{ + [Test] + public void GetAssetByGlobalTGITest() + { + TestCore.Initialize(); + var contentManager = ContentManager.Instance; + contentManager.AddPackage("TestAssets/TestPackage.package"); + var stringAsset = contentManager.GetAsset(new ResourceKey(1, "testpackage", TypeIDs.STR)); + Assert.IsNotNull(stringAsset); + } + + [Test] + public void ChangesEditAssetTest() + { + TestCore.Initialize(); + var contentManager = ContentManager.Instance; + contentManager.AddPackage("TestAssets/TestPackage.package"); + var stringAsset = contentManager.GetAsset(new ResourceKey(1, "testpackage", TypeIDs.STR)); + Assert.IsNotNull(stringAsset); + + var stringAssetClone = stringAsset.Clone() as StringSetAsset; + stringAssetClone.StringData.Strings[Languages.USEnglish][0].Value = "Edited Value"; + stringAssetClone.Save(); + + stringAsset = contentManager.GetAsset(new ResourceKey(1, "testpackage", TypeIDs.STR)); + Assert.AreEqual(stringAsset.GetString(0), "Edited Value"); + } + + [Test] + public void ChangesDeleteAssetTest() + { + TestCore.Initialize(); + var contentManager = ContentManager.Instance; + contentManager.AddPackage("TestAssets/TestPackage.package"); + var stringAsset = contentManager.GetAsset(new ResourceKey(1, "testpackage", TypeIDs.STR)); + Assert.IsNotNull(stringAsset); + + stringAsset.Delete(); + + stringAsset = contentManager.GetAsset(new ResourceKey(1, "testpackage", TypeIDs.STR)); + Assert.IsNull(stringAsset); + } +} diff --git a/Assets/Tests/OpenTS2/Content/ContentProviderTest.cs.meta b/Assets/Tests/OpenTS2/Content/ContentManagerTest.cs.meta similarity index 100% rename from Assets/Tests/OpenTS2/Content/ContentProviderTest.cs.meta rename to Assets/Tests/OpenTS2/Content/ContentManagerTest.cs.meta diff --git a/Assets/Tests/OpenTS2/Content/ContentProviderTest.cs b/Assets/Tests/OpenTS2/Content/ContentProviderTest.cs deleted file mode 100644 index 1cfd2f1c..00000000 --- a/Assets/Tests/OpenTS2/Content/ContentProviderTest.cs +++ /dev/null @@ -1,53 +0,0 @@ -using NUnit.Framework; -using OpenTS2.Client; -using OpenTS2.Common; -using OpenTS2.Content; -using OpenTS2.Content.DBPF; -using OpenTS2.Engine; -using OpenTS2.Files; -using OpenTS2.Files.Formats.DBPF; - -public class ContentProviderTest -{ - [Test] - public void GetAssetByGlobalTGITest() - { - TestMain.Initialize(); - var contentProvider = ContentProvider.Get(); - contentProvider.AddPackage("TestAssets/TestPackage.package"); - var stringAsset = contentProvider.GetAsset(new ResourceKey(1, "testpackage", TypeIDs.STR)); - Assert.IsNotNull(stringAsset); - } - - [Test] - public void ChangesEditAssetTest() - { - TestMain.Initialize(); - var contentProvider = ContentProvider.Get(); - contentProvider.AddPackage("TestAssets/TestPackage.package"); - var stringAsset = contentProvider.GetAsset(new ResourceKey(1, "testpackage", TypeIDs.STR)); - Assert.IsNotNull(stringAsset); - - var stringAssetClone = stringAsset.Clone() as StringSetAsset; - stringAssetClone.StringData.Strings[Languages.USEnglish][0].Value = "Edited Value"; - stringAssetClone.Save(); - - stringAsset = contentProvider.GetAsset(new ResourceKey(1, "testpackage", TypeIDs.STR)); - Assert.AreEqual(stringAsset.GetString(0), "Edited Value"); - } - - [Test] - public void ChangesDeleteAssetTest() - { - TestMain.Initialize(); - var contentProvider = ContentProvider.Get(); - contentProvider.AddPackage("TestAssets/TestPackage.package"); - var stringAsset = contentProvider.GetAsset(new ResourceKey(1, "testpackage", TypeIDs.STR)); - Assert.IsNotNull(stringAsset); - - stringAsset.Delete(); - - stringAsset = contentProvider.GetAsset(new ResourceKey(1, "testpackage", TypeIDs.STR)); - Assert.IsNull(stringAsset); - } -} diff --git a/Assets/Tests/OpenTS2/Content/DBPF/Scenegraph/ScenegraphTextureAssetTest.cs b/Assets/Tests/OpenTS2/Content/DBPF/Scenegraph/ScenegraphTextureAssetTest.cs index fea761d6..726fc6ac 100644 --- a/Assets/Tests/OpenTS2/Content/DBPF/Scenegraph/ScenegraphTextureAssetTest.cs +++ b/Assets/Tests/OpenTS2/Content/DBPF/Scenegraph/ScenegraphTextureAssetTest.cs @@ -23,7 +23,7 @@ public void TestSuccessfullyConvertsSquareDxt3Image() var mip = new ImageMip[] { new ByteArrayMip(imageData) }; var subImage = new SubImage(mip, Color.white, 1.0f); - var toTexture = ScenegraphTextureAsset.SubImageToTexture(ContentProvider.Get(), ScenegraphTextureFormat.DXT3, + var toTexture = ScenegraphTextureAsset.SubImageToTexture(ScenegraphTextureFormat.DXT3, 128, 128, subImage); var actualImage = new Texture2D(128, 128, TextureFormat.RGBA32, mipChain:false); @@ -45,7 +45,7 @@ public void TestSuccessfullyConvertsNonSquareDxt3Image() var mip = new ImageMip[] { new ByteArrayMip(imageData) }; var subImage = new SubImage(mip, Color.white, 1.0f); - var toTexture = ScenegraphTextureAsset.SubImageToTexture(ContentProvider.Get(), ScenegraphTextureFormat.DXT3, + var toTexture = ScenegraphTextureAsset.SubImageToTexture(ScenegraphTextureFormat.DXT3, 256, 128, subImage); var actualImage = new Texture2D(128, 128, TextureFormat.RGBA32, mipChain:false); diff --git a/Assets/Tests/OpenTS2/Content/DBPF/StringSetTest.cs b/Assets/Tests/OpenTS2/Content/DBPF/StringSetTest.cs index 1f07e992..d8f1f694 100644 --- a/Assets/Tests/OpenTS2/Content/DBPF/StringSetTest.cs +++ b/Assets/Tests/OpenTS2/Content/DBPF/StringSetTest.cs @@ -1,7 +1,7 @@ using NUnit.Framework; using OpenTS2.Content.DBPF; -using OpenTS2.Client; using System.Collections.Generic; +using OpenTS2.Content; public class StringSetTest { diff --git a/Assets/Tests/OpenTS2/Files/Formats/DBPF/DBPFFileTest.cs b/Assets/Tests/OpenTS2/Files/Formats/DBPF/DBPFFileTest.cs index 9af499a1..5fe4abb5 100644 --- a/Assets/Tests/OpenTS2/Files/Formats/DBPF/DBPFFileTest.cs +++ b/Assets/Tests/OpenTS2/Files/Formats/DBPF/DBPFFileTest.cs @@ -60,7 +60,7 @@ public void DBPFFileSaveLoadTest() [Test] public void DBPPFFileSaveCompressedEntryTest() { - TestMain.Initialize(); + TestCore.Initialize(); var packageSavePath = "TestFiles/TestPackage.package"; var packageLoadPath = "TestAssets/TestPackage.package"; var package = new DBPFFile(packageLoadPath); diff --git a/Assets/Tests/OpenTS2/Files/Formats/DBPF/EffectsCodecTest.cs b/Assets/Tests/OpenTS2/Files/Formats/DBPF/EffectsCodecTest.cs index 250593bd..5e1775fc 100644 --- a/Assets/Tests/OpenTS2/Files/Formats/DBPF/EffectsCodecTest.cs +++ b/Assets/Tests/OpenTS2/Files/Formats/DBPF/EffectsCodecTest.cs @@ -12,9 +12,9 @@ public class EffectsCodecTest [OneTimeSetUp] public void SetUp() { - TestMain.Initialize(); - ContentProvider.Get().AddPackage("TestAssets/Codecs/Effects.package"); - _effectsAsset = ContentProvider.Get() + TestCore.Initialize(); + ContentManager.Instance.AddPackage("TestAssets/Codecs/Effects.package"); + _effectsAsset = ContentManager.Instance .GetAsset(new ResourceKey(instanceID: 1, groupID: GroupIDs.Effects, typeID: TypeIDs.EFFECTS)); } diff --git a/Assets/Tests/OpenTS2/Files/Formats/DBPF/LotInfoCodecTest.cs b/Assets/Tests/OpenTS2/Files/Formats/DBPF/LotInfoCodecTest.cs index e9b47d5e..a8b7a3ce 100644 --- a/Assets/Tests/OpenTS2/Files/Formats/DBPF/LotInfoCodecTest.cs +++ b/Assets/Tests/OpenTS2/Files/Formats/DBPF/LotInfoCodecTest.cs @@ -11,20 +11,20 @@ public class LotInfoCodecTest [SetUp] public void SetUp() { - TestMain.Initialize(); - _groupID = ContentProvider.Get().AddPackage("TestAssets/Codecs/LotInfo.package").GroupID; + TestCore.Initialize(); + _groupID = ContentManager.Instance.AddPackage("TestAssets/Codecs/LotInfo.package").GroupID; } [Test] public void TestSuccessfullyLoadsRegularLot() { - var lotInfoAsset = ContentProvider.Get() + var lotInfoAsset = ContentManager.Instance .GetAsset(new ResourceKey(0x3, _groupID, TypeIDs.LOT_INFO)); Assert.That(lotInfoAsset.LotId, Is.EqualTo(3)); - Assert.That(lotInfoAsset.LotName, Is.EqualTo("1 Tesla Court")); - Assert.That(lotInfoAsset.LotDescription, Is.EqualTo("1 Tesla Court")); + Assert.That(lotInfoAsset.BaseLotInfo.LotName, Is.EqualTo("1 Tesla Court")); + Assert.That(lotInfoAsset.BaseLotInfo.LotDescription, Is.EqualTo("1 Tesla Court")); Assert.That(lotInfoAsset.LocationX, Is.EqualTo(54)); Assert.That(lotInfoAsset.LocationY, Is.EqualTo(71)); @@ -37,13 +37,13 @@ public void TestSuccessfullyLoadsRegularLot() [Test] public void TestSuccessfullyLoadsBusinessLot() { - var lotInfoAsset = ContentProvider.Get() + var lotInfoAsset = ContentManager.Instance .GetAsset(new ResourceKey(0x22, _groupID, TypeIDs.LOT_INFO)); Assert.That(lotInfoAsset.LotId, Is.EqualTo(0x22)); - Assert.That(lotInfoAsset.LotName, Is.EqualTo("153 Main Street")); - Assert.That(lotInfoAsset.LotDescription, Is.EqualTo("")); + Assert.That(lotInfoAsset.BaseLotInfo.LotName, Is.EqualTo("153 Main Street")); + Assert.That(lotInfoAsset.BaseLotInfo.LotDescription, Is.EqualTo("")); Assert.That(lotInfoAsset.LocationX, Is.EqualTo(41)); Assert.That(lotInfoAsset.LocationY, Is.EqualTo(76)); diff --git a/Assets/Tests/OpenTS2/Files/Formats/DBPF/LotObjectCodecTest.cs b/Assets/Tests/OpenTS2/Files/Formats/DBPF/LotObjectCodecTest.cs index 41240792..87e47477 100644 --- a/Assets/Tests/OpenTS2/Files/Formats/DBPF/LotObjectCodecTest.cs +++ b/Assets/Tests/OpenTS2/Files/Formats/DBPF/LotObjectCodecTest.cs @@ -12,14 +12,14 @@ public class LotObjectCodecTest [SetUp] public void SetUp() { - TestMain.Initialize(); - _groupID = ContentProvider.Get().AddPackage("TestAssets/Codecs/LotObject.package").GroupID; + TestCore.Initialize(); + _groupID = ContentManager.Instance.AddPackage("TestAssets/Codecs/LotObject.package").GroupID; } [Test] public void TestSuccessfullyLoadsLotObject() { - var lotObjectAsset = ContentProvider.Get() + var lotObjectAsset = ContentManager.Instance .GetAsset(new ResourceKey(199, _groupID, TypeIDs.LOT_OBJECT)); Assert.IsNotNull(lotObjectAsset); @@ -38,7 +38,7 @@ public void TestSuccessfullyLoadsLotObject() [Test] public void TestSuccessfullyLoadsAnimatableObject() { - var lotObjectAsset = ContentProvider.Get() + var lotObjectAsset = ContentManager.Instance .GetAsset(new ResourceKey(255, _groupID, TypeIDs.LOT_OBJECT)); var lotObject = lotObjectAsset.Object; diff --git a/Assets/Tests/OpenTS2/Files/Formats/DBPF/NeighborhoodDecorationsCodecTest.cs b/Assets/Tests/OpenTS2/Files/Formats/DBPF/NeighborhoodDecorationsCodecTest.cs index acb722ea..ea6fba95 100644 --- a/Assets/Tests/OpenTS2/Files/Formats/DBPF/NeighborhoodDecorationsCodecTest.cs +++ b/Assets/Tests/OpenTS2/Files/Formats/DBPF/NeighborhoodDecorationsCodecTest.cs @@ -10,14 +10,14 @@ public class NeighborhoodDecorationsCodecTest [SetUp] public void SetUp() { - TestMain.Initialize(); - ContentProvider.Get().AddPackage("TestAssets/Codecs/NeighborhoodDecorations.package"); + TestCore.Initialize(); + ContentManager.Instance.AddPackage("TestAssets/Codecs/NeighborhoodDecorations.package"); } [Test] public void TestSuccessfullyLoadsDecorations() { - var decorationsAsset = ContentProvider.Get() + var decorationsAsset = ContentManager.Instance .GetAssetsOfType(TypeIDs.NHOOD_DECORATIONS).Single(); Assert.That(decorationsAsset.FloraDecorations.Length, Is.EqualTo(1208)); diff --git a/Assets/Tests/OpenTS2/Files/Formats/DBPF/NeighborhoodObjectCodecTest.cs b/Assets/Tests/OpenTS2/Files/Formats/DBPF/NeighborhoodObjectCodecTest.cs index 883c67e2..655aa9a0 100644 --- a/Assets/Tests/OpenTS2/Files/Formats/DBPF/NeighborhoodObjectCodecTest.cs +++ b/Assets/Tests/OpenTS2/Files/Formats/DBPF/NeighborhoodObjectCodecTest.cs @@ -9,14 +9,14 @@ public class NeighborhoodObjectCodecTest [SetUp] public void SetUp() { - TestMain.Initialize(); - ContentProvider.Get().AddPackage("TestAssets/Codecs/NeighborhoodDecorations.package"); + TestCore.Initialize(); + ContentManager.Instance.AddPackage("TestAssets/Codecs/NeighborhoodDecorations.package"); } [Test] public void TestSuccessfullyLoadsNeighborhoodObject() { - var objectAsset = ContentProvider.Get() + var objectAsset = ContentManager.Instance .GetAssetsOfType(TypeIDs.NHOOD_OBJECT).Single(); Assert.That(objectAsset.ModelName, Is.EqualTo("ufoCrash_cres")); diff --git a/Assets/Tests/OpenTS2/Files/Formats/DBPF/ObjectModuleCodecTest.cs b/Assets/Tests/OpenTS2/Files/Formats/DBPF/ObjectModuleCodecTest.cs new file mode 100644 index 00000000..ae2e9630 --- /dev/null +++ b/Assets/Tests/OpenTS2/Files/Formats/DBPF/ObjectModuleCodecTest.cs @@ -0,0 +1,26 @@ +using NUnit.Framework; +using OpenTS2.Common; +using OpenTS2.Content; +using OpenTS2.Content.DBPF; +using OpenTS2.Files.Formats.DBPF; + +public class ObjectModuleCodecTest +{ + private uint _groupID; + + [SetUp] + public void SetUp() + { + TestCore.Initialize(); + _groupID = ContentManager.Instance.AddPackage("TestAssets/Codecs/ObjCodecs.package").GroupID; + } + + [Test] + public void TestSuccessfullyLoadsObjectModule() + { + var objectModuleAsset = ContentManager.Instance + .GetAsset(new ResourceKey(0x1, _groupID, TypeIDs.OBJM)); + + Assert.That(objectModuleAsset, Is.Not.Null); + } +} \ No newline at end of file diff --git a/Assets/Tests/OpenTS2/Files/Formats/DBPF/ObjectModuleCodecTest.cs.meta b/Assets/Tests/OpenTS2/Files/Formats/DBPF/ObjectModuleCodecTest.cs.meta new file mode 100644 index 00000000..3236872a --- /dev/null +++ b/Assets/Tests/OpenTS2/Files/Formats/DBPF/ObjectModuleCodecTest.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: c290fd6845f2442c94c96b4a69ddddc3 +timeCreated: 1727972116 \ No newline at end of file diff --git a/Assets/Tests/OpenTS2/Files/Formats/DBPF/ObjectSaveTypeTableCodecTest.cs b/Assets/Tests/OpenTS2/Files/Formats/DBPF/ObjectSaveTypeTableCodecTest.cs new file mode 100644 index 00000000..a4cb8d67 --- /dev/null +++ b/Assets/Tests/OpenTS2/Files/Formats/DBPF/ObjectSaveTypeTableCodecTest.cs @@ -0,0 +1,31 @@ +using NUnit.Framework; +using OpenTS2.Common; +using OpenTS2.Content; +using OpenTS2.Content.DBPF; +using OpenTS2.Files.Formats.DBPF; + +public class ObjectSaveTypeTableCodecTest +{ + private uint _groupID; + + [SetUp] + public void SetUp() + { + TestCore.Initialize(); + _groupID = ContentManager.Instance.AddPackage("TestAssets/Codecs/ObjCodecs.package").GroupID; + } + + [Test] + public void TestSuccessfullyLoadsSaveTypeTable() + { + var tableAsset = ContentManager.Instance + .GetAsset(new ResourceKey(0x0, _groupID, TypeIDs.OBJ_SAVE_TYPE_TABLE)); + + Assert.That(tableAsset, Is.Not.Null); + + var firstSelector = tableAsset.Selectors[0]; + Assert.That(firstSelector.objectGuid, Is.EqualTo(0xD20C0AEE)); + Assert.That(firstSelector.saveType, Is.EqualTo(1)); + Assert.That(firstSelector.catalogResourceName, Is.EqualTo("*Trash Can - Outside")); + } +} \ No newline at end of file diff --git a/Assets/Tests/OpenTS2/Files/Formats/DBPF/ObjectSaveTypeTableCodecTest.cs.meta b/Assets/Tests/OpenTS2/Files/Formats/DBPF/ObjectSaveTypeTableCodecTest.cs.meta new file mode 100644 index 00000000..31fcedaf --- /dev/null +++ b/Assets/Tests/OpenTS2/Files/Formats/DBPF/ObjectSaveTypeTableCodecTest.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 8b7ee44651ab4930babee2c290817eac +timeCreated: 1728009600 \ No newline at end of file diff --git a/Assets/Tests/OpenTS2/Files/Formats/DBPF/Scenegraph/Codecs/ScenegraphAnimationCodecTest.cs b/Assets/Tests/OpenTS2/Files/Formats/DBPF/Scenegraph/Codecs/ScenegraphAnimationCodecTest.cs index 9f9cde63..9cb80cb8 100644 --- a/Assets/Tests/OpenTS2/Files/Formats/DBPF/Scenegraph/Codecs/ScenegraphAnimationCodecTest.cs +++ b/Assets/Tests/OpenTS2/Files/Formats/DBPF/Scenegraph/Codecs/ScenegraphAnimationCodecTest.cs @@ -14,14 +14,14 @@ public class ScenegraphAnimationCodecTest [SetUp] public void SetUp() { - TestMain.Initialize(); - ContentProvider.Get().AddPackage("TestAssets/Scenegraph/animation.package"); + TestCore.Initialize(); + ContentManager.Instance.AddPackage("TestAssets/Scenegraph/animation.package"); } [Test] public void TestLoadsAnimationNode() { - var animationAsset = ContentProvider.Get() + var animationAsset = ContentManager.Instance .GetAsset(new ResourceKey("a2o-pinball-play-lose_anim", GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_ANIM)); Assert.IsNotNull(animationAsset); @@ -36,7 +36,7 @@ public void TestLoadsAnimationNode() [Test] public void TestLoadsAnimationAndHasCorrectChannels() { - var animationAsset = ContentProvider.Get() + var animationAsset = ContentManager.Instance .GetAsset(new ResourceKey("o-vehiclePizza-driveOff_anim", GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_ANIM)); @@ -116,7 +116,7 @@ private static AnimResourceConstBlock.SharedChannel[] GetChannelsByName(AnimReso [Test] public void TestInverseKinematicChainChannelsAreCorrect() { - var animationAsset = ContentProvider.Get() + var animationAsset = ContentManager.Instance .GetAsset(new ResourceKey("a2o-exerciseMachine-benchPress-start_anim", GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_ANIM)); @@ -168,7 +168,7 @@ public void TestInverseKinematicChainChannelsAreCorrect() [Test] public void TestLoadsInverseKinematicChains() { - var animationAsset = ContentProvider.Get() + var animationAsset = ContentManager.Instance .GetAsset(new ResourceKey("a2o-pinball-play-lose_anim", GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_ANIM)); @@ -261,7 +261,7 @@ public void TestLoadsInverseKinematicChains() [Test] public void LoadsInverseKinematicChainsWithMultipleTargets() { - var animationAsset = ContentProvider.Get() + var animationAsset = ContentManager.Instance .GetAsset(new ResourceKey("a2o-exerciseMachine-benchPress-start_anim", GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_ANIM)); diff --git a/Assets/Tests/OpenTS2/Files/Formats/DBPF/Scenegraph/Codecs/ScenegraphGeometryNodeCodecTest.cs b/Assets/Tests/OpenTS2/Files/Formats/DBPF/Scenegraph/Codecs/ScenegraphGeometryNodeCodecTest.cs index 2c5175e3..db9ecfbe 100644 --- a/Assets/Tests/OpenTS2/Files/Formats/DBPF/Scenegraph/Codecs/ScenegraphGeometryNodeCodecTest.cs +++ b/Assets/Tests/OpenTS2/Files/Formats/DBPF/Scenegraph/Codecs/ScenegraphGeometryNodeCodecTest.cs @@ -9,14 +9,14 @@ public class ScenegraphGeometryNodeCodecTest [SetUp] public void SetUp() { - TestMain.Initialize(); - ContentProvider.Get().AddPackage("TestAssets/Scenegraph/teapot_model.package"); + TestCore.Initialize(); + ContentManager.Instance.AddPackage("TestAssets/Scenegraph/teapot_model.package"); } [Test] public void TestLoadsGeometryNode() { - var geometryNodeAsset = ContentProvider.Get() + var geometryNodeAsset = ContentManager.Instance .GetAsset(new ResourceKey("teapot_tslocator_gmnd", 0x1C0532FA, TypeIDs.SCENEGRAPH_GMND)); diff --git a/Assets/Tests/OpenTS2/Files/Formats/DBPF/Scenegraph/Codecs/ScenegraphMaterialDefinitionCodecTest.cs b/Assets/Tests/OpenTS2/Files/Formats/DBPF/Scenegraph/Codecs/ScenegraphMaterialDefinitionCodecTest.cs index df08e95e..ce045e39 100644 --- a/Assets/Tests/OpenTS2/Files/Formats/DBPF/Scenegraph/Codecs/ScenegraphMaterialDefinitionCodecTest.cs +++ b/Assets/Tests/OpenTS2/Files/Formats/DBPF/Scenegraph/Codecs/ScenegraphMaterialDefinitionCodecTest.cs @@ -10,14 +10,14 @@ public class ScenegraphMaterialDefinitionCodecTest [SetUp] public void SetUp() { - TestMain.Initialize(); - ContentProvider.Get().AddPackage("TestAssets/Scenegraph/material_definition.package"); + TestCore.Initialize(); + ContentManager.Instance.AddPackage("TestAssets/Scenegraph/material_definition.package"); } [Test] public void TestLoadsMaterialDefinitionSuccessfully() { - var materialAsset = ContentProvider.Get() + var materialAsset = ContentManager.Instance .GetAsset(new ResourceKey("ufocrash_cabin_txmt", 0x1C0532FA, TypeIDs.SCENEGRAPH_TXMT)); diff --git a/Assets/Tests/OpenTS2/Files/Formats/DBPF/Scenegraph/Codecs/ScenegraphModelCodecTest.cs b/Assets/Tests/OpenTS2/Files/Formats/DBPF/Scenegraph/Codecs/ScenegraphModelCodecTest.cs index e288e8f3..d71a861b 100644 --- a/Assets/Tests/OpenTS2/Files/Formats/DBPF/Scenegraph/Codecs/ScenegraphModelCodecTest.cs +++ b/Assets/Tests/OpenTS2/Files/Formats/DBPF/Scenegraph/Codecs/ScenegraphModelCodecTest.cs @@ -10,15 +10,15 @@ public class ScenegraphModelCodecTest [SetUp] public void SetUp() { - TestMain.Initialize(); - ContentProvider.Get().AddPackage("TestAssets/Scenegraph/teapot_model.package"); + TestCore.Initialize(); + ContentManager.Instance.AddPackage("TestAssets/Scenegraph/teapot_model.package"); } [Test] public void TestLoadsTeapotModelWithCorrectVerticesAndFaceCount() { var modelAsset = - ContentProvider.Get().GetAsset(new ResourceKey("teapot_tslocator_gmdc", 0x1C0532FA, + ContentManager.Instance.GetAsset(new ResourceKey("teapot_tslocator_gmdc", 0x1C0532FA, TypeIDs.SCENEGRAPH_GMDC)); // There are technically ways to compare meshes properly but just use the face/vertex count here as a diff --git a/Assets/Tests/OpenTS2/Files/Formats/DBPF/Scenegraph/Codecs/ScenegraphResourceNodeCodecTest.cs b/Assets/Tests/OpenTS2/Files/Formats/DBPF/Scenegraph/Codecs/ScenegraphResourceNodeCodecTest.cs index 0e70eaa5..853695f1 100644 --- a/Assets/Tests/OpenTS2/Files/Formats/DBPF/Scenegraph/Codecs/ScenegraphResourceNodeCodecTest.cs +++ b/Assets/Tests/OpenTS2/Files/Formats/DBPF/Scenegraph/Codecs/ScenegraphResourceNodeCodecTest.cs @@ -11,14 +11,14 @@ public class ScenegraphResourceNodeCodecTest [SetUp] public void SetUp() { - TestMain.Initialize(); - ContentProvider.Get().AddPackage("TestAssets/Scenegraph/teapot_model.package"); + TestCore.Initialize(); + ContentManager.Instance.AddPackage("TestAssets/Scenegraph/teapot_model.package"); } [Test] public void LoadsResourceNode() { - var node = ContentProvider.Get() + var node = ContentManager.Instance .GetAsset(new ResourceKey("ufoCrash_cres", 0x1C0532FA, TypeIDs.SCENEGRAPH_CRES)); var shapeRef = node.ResourceCollection.GetBlockOfType(); diff --git a/Assets/Tests/OpenTS2/Files/Formats/DBPF/Scenegraph/Codecs/ScenegraphShapeCodecTest.cs b/Assets/Tests/OpenTS2/Files/Formats/DBPF/Scenegraph/Codecs/ScenegraphShapeCodecTest.cs index 393c3e5d..5c5b1731 100644 --- a/Assets/Tests/OpenTS2/Files/Formats/DBPF/Scenegraph/Codecs/ScenegraphShapeCodecTest.cs +++ b/Assets/Tests/OpenTS2/Files/Formats/DBPF/Scenegraph/Codecs/ScenegraphShapeCodecTest.cs @@ -11,14 +11,14 @@ public class ScenegraphShapeCodecTest [SetUp] public void SetUp() { - TestMain.Initialize(); - ContentProvider.Get().AddPackage("TestAssets/Scenegraph/teapot_model.package"); + TestCore.Initialize(); + ContentManager.Instance.AddPackage("TestAssets/Scenegraph/teapot_model.package"); } [Test] public void TestLoadsShapeNode() { - var node = ContentProvider.Get() + var node = ContentManager.Instance .GetAsset(new ResourceKey("ufoCrash_ufo_shpe", 0x1C0532FA, TypeIDs.SCENEGRAPH_SHPE)); Assert.That(node.ShapeBlock.Resource.ResourceName, Is.EqualTo("ufoCrash_ufo_shpe")); diff --git a/Assets/Tests/OpenTS2/Files/Formats/DBPF/Scenegraph/Codecs/ScenegraphTextureCodecTest.cs b/Assets/Tests/OpenTS2/Files/Formats/DBPF/Scenegraph/Codecs/ScenegraphTextureCodecTest.cs index 8729b1a8..711fc295 100644 --- a/Assets/Tests/OpenTS2/Files/Formats/DBPF/Scenegraph/Codecs/ScenegraphTextureCodecTest.cs +++ b/Assets/Tests/OpenTS2/Files/Formats/DBPF/Scenegraph/Codecs/ScenegraphTextureCodecTest.cs @@ -13,17 +13,17 @@ public class ScenegraphTextureCodecTest [SetUp] public void SetUp() { - TestMain.Initialize(); - ContentProvider.Get().AddPackage("TestAssets/Scenegraph/textures.package"); + TestCore.Initialize(); + ContentManager.Instance.AddPackage("TestAssets/Scenegraph/textures.package"); } [Test] public void TestLoadsTexturesWithNoLifo() { var textureAsset = - ContentProvider.Get().GetAsset(new ResourceKey("brick_dxt1_no_lifo_txtr", 0x1C0532FA, + ContentManager.Instance.GetAsset(new ResourceKey("brick_dxt1_no_lifo_txtr", 0x1C0532FA, TypeIDs.SCENEGRAPH_TXTR)); - var texture = textureAsset.GetSelectedImageAsUnityTexture(ContentProvider.Get()); + var texture = textureAsset.GetSelectedImageAsUnityTexture(); Assert.That(texture.width, Is.EqualTo(128)); Assert.That(texture.height, Is.EqualTo(128)); @@ -33,7 +33,7 @@ public void TestLoadsTexturesWithNoLifo() public void TestLoadedImageBlockWithNoLifoHasCorrectDetails() { var textureAsset = - ContentProvider.Get().GetAsset(new ResourceKey("brick_dxt1_no_lifo_txtr", 0x1C0532FA, + ContentManager.Instance.GetAsset(new ResourceKey("brick_dxt1_no_lifo_txtr", 0x1C0532FA, TypeIDs.SCENEGRAPH_TXTR)); var imageBlock = textureAsset.ImageDataBlock; @@ -54,9 +54,9 @@ public void TestLoadedImageBlockWithNoLifoHasCorrectDetails() public void TestLoadsTextureWithLifo() { var textureAsset = - ContentProvider.Get().GetAsset(new ResourceKey("brick_dxt1_txtr", 0x1C0532FA, + ContentManager.Instance.GetAsset(new ResourceKey("brick_dxt1_txtr", 0x1C0532FA, TypeIDs.SCENEGRAPH_TXTR)); - var texture = textureAsset.GetSelectedImageAsUnityTexture(ContentProvider.Get()); + var texture = textureAsset.GetSelectedImageAsUnityTexture(); Assert.That(texture.width, Is.EqualTo(256)); Assert.That(texture.height, Is.EqualTo(256)); @@ -66,7 +66,7 @@ public void TestLoadsTextureWithLifo() public void TestLoadedImageBlockWithLifoHasCorrectDetails() { var textureAsset = - ContentProvider.Get().GetAsset(new ResourceKey("brick_dxt1_txtr", 0x1C0532FA, + ContentManager.Instance.GetAsset(new ResourceKey("brick_dxt1_txtr", 0x1C0532FA, TypeIDs.SCENEGRAPH_TXTR)); var imageBlock = textureAsset.ImageDataBlock; @@ -97,11 +97,11 @@ public void TestLoadsTextureThatSqueezesToOnePixel() // but we can't have a 1x0 resolution texture, so gotta make sure we clamp that lower value to at least 1 // pixel :) var textureAsset = - ContentProvider.Get().GetAsset(new ResourceKey("small_non_square_txtr", 0x1C0532FA, + ContentManager.Instance.GetAsset(new ResourceKey("small_non_square_txtr", 0x1C0532FA, TypeIDs.SCENEGRAPH_TXTR)); // Check that the smallest mip is a 1x1 image. - var texture = textureAsset.GetSelectedImageAsUnityTexture(ContentProvider.Get()); + var texture = textureAsset.GetSelectedImageAsUnityTexture(); Assert.That(texture.GetPixels32(5).Length, Is.EqualTo(1)); } @@ -110,10 +110,10 @@ public void TestLoadsSixteenBySixtyFourDxt3Texture() { // DXT3 blocks are 4x4 but in this situation we end up with a width of 2 and height of 8. Make sure our block // iteration loop can handle that. - var textureAsset = ContentProvider.Get().GetAsset(new ResourceKey("neighborhood-stopsign_txtr", 0x1C0532FA, + var textureAsset = ContentManager.Instance.GetAsset(new ResourceKey("neighborhood-stopsign_txtr", 0x1C0532FA, TypeIDs.SCENEGRAPH_TXTR)); - var texture = textureAsset.GetSelectedImageAsUnityTexture(ContentProvider.Get()); + var texture = textureAsset.GetSelectedImageAsUnityTexture(); Assert.That(texture.GetPixels32(6).Length, Is.EqualTo(1)); } } \ No newline at end of file diff --git a/Assets/Tests/OpenTS2/Files/Formats/DBPF/SimsObjectCodecTest.cs b/Assets/Tests/OpenTS2/Files/Formats/DBPF/SimsObjectCodecTest.cs new file mode 100644 index 00000000..e2b53acf --- /dev/null +++ b/Assets/Tests/OpenTS2/Files/Formats/DBPF/SimsObjectCodecTest.cs @@ -0,0 +1,28 @@ +using System.Linq; +using NUnit.Framework; +using OpenTS2.Common; +using OpenTS2.Content; +using OpenTS2.Content.DBPF; +using OpenTS2.Files.Formats.DBPF; + +public class SimsObjectCodecTest +{ + private uint _groupID; + + [SetUp] + public void SetUp() + { + TestCore.Initialize(); + _groupID = ContentManager.Instance.AddPackage("TestAssets/Codecs/ObjCodecs.package").GroupID; + } + + [Test] + public void TestSuccessfullyLoadsSimsObject() + { + // Pancake object. + var objectAsset = ContentManager.Instance.GetAsset( + new ResourceKey(163, _groupID, TypeIDs.XOBJ)); + + Assert.That(objectAsset, Is.Not.Null); + } +} \ No newline at end of file diff --git a/Assets/Tests/OpenTS2/Files/Formats/DBPF/SimsObjectCodecTest.cs.meta b/Assets/Tests/OpenTS2/Files/Formats/DBPF/SimsObjectCodecTest.cs.meta new file mode 100644 index 00000000..08115342 --- /dev/null +++ b/Assets/Tests/OpenTS2/Files/Formats/DBPF/SimsObjectCodecTest.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 13359c34be754888864a20da2042ea57 +timeCreated: 1727122336 \ No newline at end of file diff --git a/Assets/Tests/OpenTS2/SimAntics/SimAnticsLuaTest.cs b/Assets/Tests/OpenTS2/SimAntics/SimAnticsLuaTest.cs index 2c8974cc..d335b70a 100644 --- a/Assets/Tests/OpenTS2/SimAntics/SimAnticsLuaTest.cs +++ b/Assets/Tests/OpenTS2/SimAntics/SimAnticsLuaTest.cs @@ -18,8 +18,8 @@ public class SimAnticsLuaTest [SetUp] public void SetUp() { - TestMain.Initialize(); - _groupID = ContentProvider.Get().AddPackage("TestAssets/SimAntics/lua.package").GroupID; + TestCore.Initialize(); + _groupID = ContentManager.Instance.AddPackage("TestAssets/SimAntics/lua.package").GroupID; } [Test] diff --git a/Assets/Tests/OpenTS2/SimAntics/SimAnticsTest.cs b/Assets/Tests/OpenTS2/SimAntics/SimAnticsTest.cs index 7d23b023..ea81d5eb 100644 --- a/Assets/Tests/OpenTS2/SimAntics/SimAnticsTest.cs +++ b/Assets/Tests/OpenTS2/SimAntics/SimAnticsTest.cs @@ -18,8 +18,8 @@ public class SimAnticsTest [SetUp] public void SetUp() { - TestMain.Initialize(); - _groupID = ContentProvider.Get().AddPackage("TestAssets/SimAntics/bhav.package").GroupID; + TestCore.Initialize(); + _groupID = ContentManager.Instance.AddPackage("TestAssets/SimAntics/bhav.package").GroupID; } [Test] @@ -89,9 +89,14 @@ public void TestBHAVThrowsOnInfiniteLoop() var stackFrame = new VMStackFrame(bhav, entity.MainThread); entity.MainThread.Frames.Push(stackFrame); - Assert.Throws(() => + Exception exception = null; + vm.ExceptionHandler += (Exception e, VMEntity ent) => { - vm.Tick(); - }); + exception = e; + }; + + vm.Tick(); + + Assert.IsInstanceOf(exception); } } diff --git a/Assets/Tests/TestMain.cs b/Assets/Tests/TestCore.cs similarity index 55% rename from Assets/Tests/TestMain.cs rename to Assets/Tests/TestCore.cs index c1c33da9..e46601bc 100644 --- a/Assets/Tests/TestMain.cs +++ b/Assets/Tests/TestCore.cs @@ -1,42 +1,31 @@ using OpenTS2.Assemblies; -using OpenTS2.Client; using OpenTS2.Content; +using OpenTS2.Engine; using OpenTS2.Files; using OpenTS2.Files.Formats.DBPF; using OpenTS2.Lua; using OpenTS2.SimAntics.Primitives; +using UnityEngine; /// /// Main initialization class for OpenTS2 unit testing. /// -public static class TestMain +public static class TestCore { - static bool s_initialized = false; - /// /// Initializes all singletons, systems and the game assembly. /// public static void Initialize() { - if (s_initialized) - Shutdown(); - var settings = new Settings() - { - CustomContentEnabled = false, - Language = Languages.USEnglish - }; + var globals = new GameGlobals(); + GameGlobals.allowCustomContent = false; var epManager = new EPManager((int)ProductFlags.BaseGame); - var contentProvider = new ContentProvider(); + var contentManager = new ContentManager(); var luaManager = new LuaManager(); - Filesystem.Initialize(new TestPathProvider(), epManager); + + Filesystem.Initialize(); CodecAttribute.Initialize(); AssemblyHelper.InitializeLoadedAssemblies(); VMPrimitiveRegistry.Initialize(); - s_initialized = true; - } - - public static void Shutdown() - { - s_initialized = false; } } \ No newline at end of file diff --git a/Assets/Tests/TestCore.cs.meta b/Assets/Tests/TestCore.cs.meta new file mode 100644 index 00000000..93086c6b --- /dev/null +++ b/Assets/Tests/TestCore.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 15b9acd2d9c2a2e4a870f1b889f2c68c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Tests/TestPathProvider.cs b/Assets/Tests/TestPathProvider.cs index 4df8ef12..82cee5ac 100644 --- a/Assets/Tests/TestPathProvider.cs +++ b/Assets/Tests/TestPathProvider.cs @@ -1,7 +1,7 @@ using OpenTS2.Content; using OpenTS2.Content.Interfaces; -public class TestPathProvider : IPathProvider +public class TestPathManager : IPathManager { public string GetBinPathForProduct(ProductFlags productFlag) { diff --git a/Assets/Tests/Tests.asmdef b/Assets/Tests/Tests.asmdef index 7680c1b6..3a99b80a 100644 --- a/Assets/Tests/Tests.asmdef +++ b/Assets/Tests/Tests.asmdef @@ -4,7 +4,7 @@ "references": [ "UnityEngine.TestRunner", "UnityEditor.TestRunner", - "ScriptsAssembly" + "OpenTS2" ], "includePlatforms": [ "Editor" diff --git a/Notes/Music.txt b/Notes/Music.txt new file mode 100644 index 00000000..2550d0eb --- /dev/null +++ b/Notes/Music.txt @@ -0,0 +1,51 @@ +Notes to make my life easier when it comes to trying to load all the radio stations and music from the game. + +----------------------------------------------------------------------------------------------------------- + +Music categories are in a Property Set XML resource + +Located at TSData/Res/Sound/Misc.package in SP9 + +Resourcekey: + +Instance ID: 0xFFD3706D +Instance (High): 0x38888A91 +Group ID: 0x4C1940C5 +Type ID: 0xEBFEE33F + +----------------------------------------------------------------------------------------------------------------- + +When adding songs to custom stations, they are referenced by their MP3 resource Instance ID and Instance ID (High) +----------------------------------------------------------------------------------------------------------------- + +Asset with mp3/sound file type has instructions on adding new stations. These are actually ini files. + +Located at TSData/Res/Sound/Misc.package in SP9 +Real ini: TSData/Sys/TSAudioUnpackedEP9.ini + +Instance ID: 0xFF579C9A +Instance (High): 0x8EA9CC5B +Group ID: 0xADD550A7 +Type ID: 0x2026960B + +Another one: +Real ini: TSData/Sys/TSAudioPackedEP9.ini + +Instance ID: 0xFFBCCA55 +Instance (High): 0xCD79214F +Group ID: 0xADD550A7 +Type ID: 0x2026960B + +Locale ini is for locale-specific tracks. + +Group ID and hash for the radio station can be generated with the OpenTS2.IDGenerator tool (Editor -> OpenTS2 -> Resource Key -> From Filename). The resulting Instance ID is the hash you want. + +When adding custom songs to a .package file, use the hash for the radio station as the Group ID and a hash of what you want the song to be localized to in english as the Instance ID (lo and hi) + +When adding station and song names on stringsets, the text has to match the hash of the song and station in US english. + +----------------------------------------------------------------------------------------------------------------- + +Maybe editing just the ini files is ok and the packed .inis can be left alone? Dunno. + +----------------------------------------------------------------------------------------------------------------- \ No newline at end of file diff --git a/Notes/Sounds.txt b/Notes/Sounds.txt new file mode 100644 index 00000000..6c4acfd4 --- /dev/null +++ b/Notes/Sounds.txt @@ -0,0 +1,34 @@ +Sound research + +Track Settings Type: 0x0B9EB87E +Binary file Type: 0x7B1ACFCD + +Track Settings file: + +XML with following properties in order: + +Sample Rate - eg 32000 +Unknown string - Always "Track"? + +There is also a binary resource with the same instance id as the Track Settings file. Does not seem to contain audio data. Maybe references the actual sound resource? + +These sounds should be loaded as AudioAssets so that they can be played like any other sound by TSAudioSource + +Replacing the Track settings file with an MP3 triggers a GetSoundDefinition error + +Replacing the binary file with an MP3 triggers a GetHitList error + +0x7B1ACFCD Must be a HitList resource. Likely contains references to sounds. + +Binary file 0x7B1ACFCD: + +4 bytes: Always 56? +4 bytes: Count +For Count loop + References to MP3/XA/etc audio assets + 4 bytes: Instance Lo + 4 bytes: Instance Hi +End loop + + +I wonder if the track settings file is optional? Seems odd to be able to override the sample rate and such when they're provided in the sounds themselves already. \ No newline at end of file diff --git a/Notes/hitlist.md b/Notes/hitlist.md new file mode 100644 index 00000000..605215da --- /dev/null +++ b/Notes/hitlist.md @@ -0,0 +1,15 @@ +# HitList resource +This resource is played by the game like any normal sound, but instead of having sound data it contains references to other audio files that will be randomly picked on playback. + +They tend to have a PropertySet file alongside them with the same Instance and Group IDs, of Type ID 0x0B9EB87E (Labeled Track Settings by SimPE) which seems to provide data about the sound such as Sample Rate. and references to other Resources. + +## Format +``` +4 Bytes: Version? Always 56 +4 Bytes: Sound count +Loop for Sound Count + Each entry is a reference to an actual audio file, such as an MP3/XA/WAV/etc. + 4 Bytes: Instance ID Low + 4 Bytes: Instance ID High +End Loop +``` \ No newline at end of file diff --git a/Notes/ui ids.txt b/Notes/ui ids.txt new file mode 100644 index 00000000..13ad308d --- /dev/null +++ b/Notes/ui ids.txt @@ -0,0 +1,2 @@ +settings: 0x49001028 +audio settings: 0x49060F01 \ No newline at end of file diff --git a/ProjectSettings/BurstAotSettings_StandaloneWindows.json b/ProjectSettings/BurstAotSettings_StandaloneWindows.json new file mode 100644 index 00000000..2144f6dc --- /dev/null +++ b/ProjectSettings/BurstAotSettings_StandaloneWindows.json @@ -0,0 +1,16 @@ +{ + "MonoBehaviour": { + "Version": 3, + "EnableBurstCompilation": true, + "EnableOptimisations": true, + "EnableSafetyChecks": false, + "EnableDebugInAllBuilds": false, + "UsePlatformSDKLinker": false, + "CpuMinTargetX32": 0, + "CpuMaxTargetX32": 0, + "CpuMinTargetX64": 0, + "CpuMaxTargetX64": 0, + "CpuTargetsX32": 6, + "CpuTargetsX64": 72 + } +} diff --git a/ProjectSettings/EditorBuildSettings.asset b/ProjectSettings/EditorBuildSettings.asset index 9ae5bf17..2edd753e 100644 --- a/ProjectSettings/EditorBuildSettings.asset +++ b/ProjectSettings/EditorBuildSettings.asset @@ -7,6 +7,9 @@ EditorBuildSettings: m_Scenes: - enabled: 1 path: Assets/Scenes/Startup.unity + guid: 1092174c2196ea14b9b0c877f334fe86 + - enabled: 1 + path: Assets/Scenes/Main Menu.unity guid: b8799d538c243b245a875e084cdcd466 - enabled: 1 path: Assets/Scenes/Neighborhood.unity diff --git a/ProjectSettings/GraphicsSettings.asset b/ProjectSettings/GraphicsSettings.asset index 54a5e35f..a6405a5c 100644 --- a/ProjectSettings/GraphicsSettings.asset +++ b/ProjectSettings/GraphicsSettings.asset @@ -30,27 +30,32 @@ GraphicsSettings: m_Shader: {fileID: 102, guid: 0000000000000000f000000000000000, type: 0} m_VideoShadersIncludeMode: 2 m_AlwaysIncludedShaders: + - {fileID: 4800000, guid: cd1c2fe69305d6340a8e116e63955e26, type: 3} + - {fileID: 4800000, guid: 75e0683a765caef42b3b3feffe1eee77, type: 3} + - {fileID: 4800000, guid: 687258d81ac22d0468c2f8b31c25f43d, type: 3} + - {fileID: 4800000, guid: 4d0461340a185194c81b99c57ca9c084, type: 3} + - {fileID: 4800000, guid: 0b96ca1818f768545967888a745b08e5, type: 3} + - {fileID: 4800000, guid: 55f7b711d4325524584831ce7bb2be79, type: 3} + - {fileID: 4800000, guid: 2d983799f8cc5724cab449e620cf6b68, type: 3} + - {fileID: 4800000, guid: 671704f76cb894247bef231623ec3b5c, type: 3} + - {fileID: 4800000, guid: 9553309111f53d545bf0ba247f244fac, type: 3} + - {fileID: 4800000, guid: 93dd8e4998118244d8c2db0d96306036, type: 3} + - {fileID: 4800000, guid: 60c13438278307349a9e38b27e0d76c2, type: 3} + - {fileID: 4800000, guid: 773f4884ae91ed84da0b590f8035b290, type: 3} + - {fileID: 4800000, guid: de5c3ee1c467ffb498220096ed43fc79, type: 3} + - {fileID: 4800000, guid: 4365b0ce5e2aaaf4db092886d75a96ea, type: 3} + - {fileID: 4800000, guid: 3d28d78029cd77e45a3596cc8dbcd999, type: 3} + - {fileID: 4800000, guid: 49b517286481f9b46abb94305786089e, type: 3} + - {fileID: 4800000, guid: f56f884b040997b419d7f04eb5b8aace, type: 3} + - {fileID: 4800000, guid: 99d4c2193a8ae8c4b9a141c07ac72fdf, type: 3} + - {fileID: 4800000, guid: 785a97f13c5450c4ca19c4009646dae2, type: 3} - {fileID: 7, guid: 0000000000000000f000000000000000, type: 0} - {fileID: 15104, guid: 0000000000000000f000000000000000, type: 0} - {fileID: 15105, guid: 0000000000000000f000000000000000, type: 0} - {fileID: 15106, guid: 0000000000000000f000000000000000, type: 0} - {fileID: 10753, guid: 0000000000000000f000000000000000, type: 0} - {fileID: 10770, guid: 0000000000000000f000000000000000, type: 0} - - {fileID: 4800000, guid: 0b96ca1818f768545967888a745b08e5, type: 3} - - {fileID: 4800000, guid: 4d0461340a185194c81b99c57ca9c084, type: 3} - - {fileID: 4800000, guid: 687258d81ac22d0468c2f8b31c25f43d, type: 3} - - {fileID: 4800000, guid: f56f884b040997b419d7f04eb5b8aace, type: 3} - - {fileID: 4800000, guid: 93dd8e4998118244d8c2db0d96306036, type: 3} - - {fileID: 4800000, guid: de5c3ee1c467ffb498220096ed43fc79, type: 3} - - {fileID: 4800000, guid: 60c13438278307349a9e38b27e0d76c2, type: 3} - - {fileID: 4800000, guid: 773f4884ae91ed84da0b590f8035b290, type: 3} - - {fileID: 4800000, guid: 9553309111f53d545bf0ba247f244fac, type: 3} - - {fileID: 4800000, guid: 671704f76cb894247bef231623ec3b5c, type: 3} - - {fileID: 4800000, guid: 2d983799f8cc5724cab449e620cf6b68, type: 3} - - {fileID: 4800000, guid: 55f7b711d4325524584831ce7bb2be79, type: 3} - - {fileID: 4800000, guid: 785a97f13c5450c4ca19c4009646dae2, type: 3} - - {fileID: 4800000, guid: 3d28d78029cd77e45a3596cc8dbcd999, type: 3} - - {fileID: 4800000, guid: 4365b0ce5e2aaaf4db092886d75a96ea, type: 3} + - {fileID: 211, guid: 0000000000000000f000000000000000, type: 0} m_PreloadedShaders: [] m_SpritesDefaultMaterial: {fileID: 10754, guid: 0000000000000000f000000000000000, type: 0} m_CustomRenderPipeline: {fileID: 0} diff --git a/ProjectSettings/ProjectSettings.asset b/ProjectSettings/ProjectSettings.asset index 946d6476..0a9c1e9a 100644 --- a/ProjectSettings/ProjectSettings.asset +++ b/ProjectSettings/ProjectSettings.asset @@ -12,7 +12,7 @@ PlayerSettings: targetDevice: 2 useOnDemandResources: 0 accelerometerFrequency: 60 - companyName: DefaultCompany + companyName: OpenTS2 productName: OpenTS2 defaultCursor: {fileID: 0} cursorHotspot: {x: 0, y: 0} @@ -153,7 +153,7 @@ PlayerSettings: androidSupportedAspectRatio: 1 androidMaxAspectRatio: 2.1 applicationIdentifier: - Standalone: com.DefaultCompany.OpenTS2 + Standalone: com.OpenTS2.OpenTS2 buildNumber: Standalone: 0 iPhone: 0 diff --git a/ProjectSettings/TagManager.asset b/ProjectSettings/TagManager.asset index 32ca3c32..058c95ee 100644 --- a/ProjectSettings/TagManager.asset +++ b/ProjectSettings/TagManager.asset @@ -11,7 +11,7 @@ TagManager: - Terrain - Water - UI - - + - NonReflective - - - diff --git a/README.md b/README.md index eb260405..1503a60e 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,8 @@ Currently a basic main menu with a neighborhood chooser is implemented. Neighbor * [MoonSharp](https://github.com/moonsharp-devs/moonsharp/) * [FreeSO](https://github.com/RHY3756547/FreeSO) * [DBPFSharp](https://github.com/0xC0000054/DBPFSharp/blob/main/src/DBPFSharp) +* [NAudio](https://github.com/naudio/NAudio) +* [NSpeex](https://github.com/aijingsun6/NSpeex) ## Similar Projects * [FreeSO](https://github.com/RHY3756547/FreeSO) - Open Source reimplementation of The Sims Online using C# and Monogame. OpenTS2 borrows a lot of code and structure from this project. @@ -40,9 +42,9 @@ This Source Code Form is subject to the terms of the Mozilla Public License, v. We follow the layout of a normal Unity project except: * `Assets/Scripts/OpenTS2` - Contains the bulk of the C# code that deals with TS2 formats and files. -* `Assets/Scripts/OpenTS2/Engine` - Unity *specific* code tends to live in here to keep it - separate from the more language-independent code in the directory. * `Assets/Tests/OpenTS2/` - Unit tests following the same directory structure as the `Scripts` folder. +* `Assets/Scenes/Test` - Tests but more at the integration level involving Unity scenes. + * `Assets/Scripts/OpenTS2/Engine/Tests` - Controller scripts for the above tests. ## Testing diff --git a/TestAssets/Codecs/ObjCodecs.package b/TestAssets/Codecs/ObjCodecs.package new file mode 100644 index 00000000..6cec784e Binary files /dev/null and b/TestAssets/Codecs/ObjCodecs.package differ diff --git a/UpgradeLog.htm b/UpgradeLog.htm new file mode 100644 index 00000000..bf44b1f8 --- /dev/null +++ b/UpgradeLog.htm @@ -0,0 +1,276 @@ + + + + Migration Report +

+ Migration Report -

\ No newline at end of file