diff --git a/build/engine/shaders/base/static.vs b/build/engine/shaders/base/static.vs
index 7519f8a490b02ee9ec8f401c5d6f3bcd0c43941b..c32007f63c091087b164bca512f03cc11a3dd8a7 100644
--- a/build/engine/shaders/base/static.vs
+++ b/build/engine/shaders/base/static.vs
@@ -45,10 +45,15 @@ VSO_SceneCommon main(VSI_Geometry IN
 	// OUT.vPosition = float4(IN.vPosition, 1.0f);
 
 	OUT.vNormal = RotateVec(qRot, IN.vNormal);
+	OUT.vTangent  = RotateVec(qRot, IN.vTangent);
+	OUT.vBinormal = RotateVec(qRot, IN.vBinormal);
 	// OUT.vNormal = IN.vNormal;
 #else
 	OUT.vPosition = mul(float4(IN.vPosition, 1.0f), g_mW);
-	OUT.vNormal = mul(IN.vNormal, (float3x3)g_mW);
+	OUT.vNormal = /*normalize(*/mul(IN.vNormal, (float3x3)g_mW)/*)*/;
+	OUT.vTangent  = /*normalize(*/mul(IN.vTangent, (float3x3)g_mW)/*)*/;
+	OUT.vBinormal = /*normalize(*/mul(IN.vBinormal, (float3x3)g_mW)/*)*/;
+
 #endif
 
 	
diff --git a/build/engine/shaders/default/default.ps b/build/engine/shaders/default/default.ps
index 0d851c06e47f08a5ef0a8d91ed5be796950c7b44..1ea443127ff45d4963e394e10742c2c4f1047b05 100644
--- a/build/engine/shaders/default/default.ps
+++ b/build/engine/shaders/default/default.ps
@@ -26,9 +26,9 @@ XMaterial MainGBuffer(PSI_XMaterial IN)
 #endif
 
 #ifdef HAS_NORMALMAP
-	OUT.vNormal = MixNormalMicro(IN.vNormal, 
-		Color2Normal(g_txNormals.Sample(g_sScene, IN.vTexUV).xyz) * g_xMaterialConstants.nm_weight
-	);
+	float3 vNormalMap = Color2Normal(g_txNormals.Sample(g_sScene, IN.vTexUV).xyz) * g_xMaterialConstants.nm_weight;
+	OUT.vNormal = MixNormalMicro(vNormalMap, IN.vTangent, IN.vBinormal, IN.vNormal);
+	//OUT.vNormal = normalize((IN.vNormal + float3(vNormalMap.xy,IN.vNormal.z)));
 #else
 	OUT.vNormal = IN.vNormal;
 #endif
@@ -58,9 +58,8 @@ XMaterial MainIllimination(PSI_XMaterial IN)
 	OUT.vEmissiveColor = fColor.xyz * fColor.w * g_xMaterialConstants.em_multiplier;
 	
 #ifdef HAS_NORMALMAP
-	OUT.vNormal = MixNormalMicro(IN.vNormal, 
-		Color2Normal(g_txNormals.Sample(g_sScene, IN.vTexUV).xyz) * g_xMaterialConstants.nm_weight
-	);
+	float3 vNormalMap = Color2Normal(g_txNormals.Sample(g_sScene, IN.vTexUV).xyz) * g_xMaterialConstants.nm_weight;
+	OUT.vNormal = MixNormalMicro(vNormalMap, IN.vTangent, IN.vBinormal, IN.vNormal);
 #else
 	OUT.vNormal = IN.vNormal;
 #endif
diff --git a/build/engine/shaders/default/terrain.ps b/build/engine/shaders/default/terrain.ps
index 162b155bf09a4a216c6b95bb8deee300808d6e0e..ae3138e70d41701e4a39934ad6bd3cc4c534dfdc 100644
--- a/build/engine/shaders/default/terrain.ps
+++ b/build/engine/shaders/default/terrain.ps
@@ -84,7 +84,9 @@ XMaterial MainGBuffer(PSI_XMaterial IN)
 	OUT.fThickness = vParams.z;
 	OUT.fAO = vParams.w;
 	
-	OUT.vNormal = MixNormalMicro(IN.vNormal, vNormal);
+	//OUT.vNormal = MixNormalMicro(IN.vNormal, vNormal);
+	OUT.vNormal = MixNormalMicro(vNormal, IN.vTangent, IN.vBinormal, IN.vNormal);
+	//OUT.vNormal = normalize((IN.vNormal + float3(vNormal.xy,IN.vNormal.z)));
 	
 	OUT.f0 = 0.004;
 	
diff --git a/build/engine/shaders/default/transparent.ps b/build/engine/shaders/default/transparent.ps
index fd011224335bfa099544d4df084bb846e81b379d..8bd5ee96a2858bb61cc020f42c2fcb19b0cf53f0 100644
--- a/build/engine/shaders/default/transparent.ps
+++ b/build/engine/shaders/default/transparent.ps
@@ -13,9 +13,9 @@ XMaterial MainTransparency(PSI_XMaterial IN)
 #ifdef HAS_NORMALMAP
 	float3 vNormal = Color2Normal(g_txNormals.Sample(g_sScene, IN.vTexUV).xyz) * g_xMaterialConstants.nm_weight;
 	
-	OUT.vNormal = MixNormalMicro(IN.vNormal, vNormal);
+	//OUT.vNormal = MixNormalMicro(IN.vNormal, vNormal);
 	// float2 vDuDv = vNormal.xy;
-	
+	OUT.vNormal = MixNormalMicro(vNormal, IN.vTangent, IN.vBinormal, IN.vNormal);
 	
 #ifdef HAS_REFRACTION
 	// float2 vDuDv = OUT.vNormal.xy;
@@ -84,9 +84,8 @@ XMaterial MainIllimination(PSI_XMaterial IN)
 	OUT.vEmissiveColor = fColor.xyz;
 	
 #ifdef HAS_NORMALMAP
-	OUT.vNormal = MixNormalMicro(IN.vNormal, 
-		Color2Normal(g_txNormals.Sample(g_sScene, IN.vTexUV).xyz) * g_xMaterialConstants.nm_weight
-	);
+	float3 vNormalMap = Color2Normal(g_txNormals.Sample(g_sScene, IN.vTexUV).xyz) * g_xMaterialConstants.nm_weight;
+	OUT.vNormal = MixNormalMicro(vNormalMap, IN.vTangent, IN.vBinormal, IN.vNormal);
 #else
 	OUT.vNormal = IN.vNormal;
 #endif
diff --git a/build/engine/shaders/mtrl.h b/build/engine/shaders/mtrl.h
index a39b98a71f7234456dad02b064db575ca6d26369..fc8d9108d47ef32e35eaf5cc569a93eea9194dc2 100644
--- a/build/engine/shaders/mtrl.h
+++ b/build/engine/shaders/mtrl.h
@@ -192,9 +192,15 @@ float GetLerpFactorDetail(float fDistance)
 }
 
 //! смешивание макронормали (модели) с микронормалью (из normal map)
-float3 MixNormalMicro(float3 vMacroNormal, float3 vMicroNormal)
+/*float3 MixNormalMicro(float3 vMacroNormal, float3 vMicroNormal)
 {
 	return normalize((vMacroNormal + float3(vMicroNormal.xy,vMacroNormal.z)));
+}*/
+
+float3 MixNormalMicro(float3 vNormalMap, float3 vTangent, float3 vBinormal, float3 vNormal)
+{
+	float3x3 mTBN = float3x3(vTangent, vBinormal, vNormal);
+	return normalize(mul(vNormalMap, mTBN));
 }
 
 //! смешивание 2 детальных текстур по маске, где r канал маски для первой детальной текстуры, а g для второй
diff --git a/build/engine/shaders/struct.h b/build/engine/shaders/struct.h
index 1fd16aceeb265abb259099c53b690581e5e9d89b..586f6c2e8b8c6d3d048726ba7ce167caf5a4e8bd 100644
--- a/build/engine/shaders/struct.h
+++ b/build/engine/shaders/struct.h
@@ -68,6 +68,8 @@ struct VSI_Geometry
 	float3 vPosition	:POSITION0;
 	float2 vTexUV	:TEXCOORD0;
 	float3 vNormal	:NORMAL0;
+	float3 vTangent	: TANGENT0;
+	float3 vBinormal	: BINORMAL0;
 };
 
 
@@ -112,6 +114,8 @@ struct VSO_SceneCommon
 	float2 vTexUV	:TEXCOORD0;
 	float3 vNormal	:TEXCOORD1;
 	float4 vPos		:TEXCOORD2;
+	float3 vTangent	:TEXCOORD3;
+	float3 vBinormal	:TEXCOORD4;
 };
 
 struct GSO_SceneShadows
diff --git a/build/engine/sounds/actor/step/default1.ogg b/build/engine/sounds/actor/step/default1.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..10bddbf3524db9d5baa225f54dbb1b7b1567be47
Binary files /dev/null and b/build/engine/sounds/actor/step/default1.ogg differ
diff --git a/build/engine/sounds/actor/step/default2.ogg b/build/engine/sounds/actor/step/default2.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..10bddbf3524db9d5baa225f54dbb1b7b1567be47
Binary files /dev/null and b/build/engine/sounds/actor/step/default2.ogg differ
diff --git a/build/engine/sounds/actor/step/default3.ogg b/build/engine/sounds/actor/step/default3.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..73a09e6a81665bd572d304d2b150b45ea63fe1d2
Binary files /dev/null and b/build/engine/sounds/actor/step/default3.ogg differ
diff --git a/build/engine/sounds/actor/step/default4.ogg b/build/engine/sounds/actor/step/default4.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..3f2e4af404716328ecf97ce14dd1b8936bae4698
Binary files /dev/null and b/build/engine/sounds/actor/step/default4.ogg differ
diff --git a/build/engine/sounds/actor/step/earth1.ogg b/build/engine/sounds/actor/step/earth1.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..35be9058f776be270fc07b29c21256af2a2d08cf
Binary files /dev/null and b/build/engine/sounds/actor/step/earth1.ogg differ
diff --git a/build/engine/sounds/actor/step/earth2.ogg b/build/engine/sounds/actor/step/earth2.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..2c86be24cdfe51c1b827992981fa468603206cc9
Binary files /dev/null and b/build/engine/sounds/actor/step/earth2.ogg differ
diff --git a/build/engine/sounds/actor/step/earth3.ogg b/build/engine/sounds/actor/step/earth3.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..a61dd0549a6f6167863832251477bc1a5d4804ee
Binary files /dev/null and b/build/engine/sounds/actor/step/earth3.ogg differ
diff --git a/build/engine/sounds/actor/step/earth4.ogg b/build/engine/sounds/actor/step/earth4.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..fe7ba8a7f10da38a5bb688d73f5df1d781473dfe
Binary files /dev/null and b/build/engine/sounds/actor/step/earth4.ogg differ
diff --git a/build/engine/sounds/actor/step/grass1.ogg b/build/engine/sounds/actor/step/grass1.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..f038d57c7acabb79c2b535e8f47f861fa80937e3
Binary files /dev/null and b/build/engine/sounds/actor/step/grass1.ogg differ
diff --git a/build/engine/sounds/actor/step/grass2.ogg b/build/engine/sounds/actor/step/grass2.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..f3d4b55338dd8b27fa8017685c595c0380dbabda
Binary files /dev/null and b/build/engine/sounds/actor/step/grass2.ogg differ
diff --git a/build/engine/sounds/actor/step/grass3.ogg b/build/engine/sounds/actor/step/grass3.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..329af390d67654b88daf923f2b079a0b85dca254
Binary files /dev/null and b/build/engine/sounds/actor/step/grass3.ogg differ
diff --git a/build/engine/sounds/actor/step/grass4.ogg b/build/engine/sounds/actor/step/grass4.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..989c27d6d14dde7a7d7435d1abd6ef0c08776c01
Binary files /dev/null and b/build/engine/sounds/actor/step/grass4.ogg differ
diff --git a/build/engine/sounds/actor/step/gravel1.ogg b/build/engine/sounds/actor/step/gravel1.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..c85b6f54783885149cb551f0b451e0f5ee3f62eb
Binary files /dev/null and b/build/engine/sounds/actor/step/gravel1.ogg differ
diff --git a/build/engine/sounds/actor/step/gravel2.ogg b/build/engine/sounds/actor/step/gravel2.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..2e0aa06f236aa1a2cadf30a8dc485091381cdc3e
Binary files /dev/null and b/build/engine/sounds/actor/step/gravel2.ogg differ
diff --git a/build/engine/sounds/actor/step/metal_plate1.ogg b/build/engine/sounds/actor/step/metal_plate1.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..fed2f89c008b638eaa51de437aa094c8df607b35
Binary files /dev/null and b/build/engine/sounds/actor/step/metal_plate1.ogg differ
diff --git a/build/engine/sounds/actor/step/metal_plate2.ogg b/build/engine/sounds/actor/step/metal_plate2.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..3c34feb6bb8f124952662c44f3f30ea77dd88453
Binary files /dev/null and b/build/engine/sounds/actor/step/metal_plate2.ogg differ
diff --git a/build/engine/sounds/actor/step/metal_plate3.ogg b/build/engine/sounds/actor/step/metal_plate3.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..10f64e0ed1697a0e3bf2a0b2a95848c6cf38344d
Binary files /dev/null and b/build/engine/sounds/actor/step/metal_plate3.ogg differ
diff --git a/build/engine/sounds/actor/step/metal_plate4.ogg b/build/engine/sounds/actor/step/metal_plate4.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..70a87c80702b5878707e3ff9229a608069d50ce4
Binary files /dev/null and b/build/engine/sounds/actor/step/metal_plate4.ogg differ
diff --git a/build/engine/sounds/actor/step/new_wood1.ogg b/build/engine/sounds/actor/step/new_wood1.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..47c65ba7dc20fd5662b26dbf2006251f306aa76b
Binary files /dev/null and b/build/engine/sounds/actor/step/new_wood1.ogg differ
diff --git a/build/engine/sounds/actor/step/new_wood2.ogg b/build/engine/sounds/actor/step/new_wood2.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..8b3a7ef404310275c0c001fbed24ae3f04242306
Binary files /dev/null and b/build/engine/sounds/actor/step/new_wood2.ogg differ
diff --git a/build/engine/sounds/actor/step/new_wood3.ogg b/build/engine/sounds/actor/step/new_wood3.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..bc86b78d3a5ca0bf2740cb2fceec9f245d316ec2
Binary files /dev/null and b/build/engine/sounds/actor/step/new_wood3.ogg differ
diff --git a/build/engine/sounds/actor/step/new_wood4.ogg b/build/engine/sounds/actor/step/new_wood4.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..1b4f161016511b0c11cb5bcfa0382288cb1fcf5a
Binary files /dev/null and b/build/engine/sounds/actor/step/new_wood4.ogg differ
diff --git a/build/engine/sounds/actor/step/t_water1.ogg b/build/engine/sounds/actor/step/t_water1.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..9f4439fa1374a449553e27cace2e27529a628f16
Binary files /dev/null and b/build/engine/sounds/actor/step/t_water1.ogg differ
diff --git a/build/engine/sounds/actor/step/t_water2.ogg b/build/engine/sounds/actor/step/t_water2.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..6917fc69f77e70d3d5e8530a72e6855a983b2397
Binary files /dev/null and b/build/engine/sounds/actor/step/t_water2.ogg differ
diff --git a/build/engine/sounds/actor/step/tin1.ogg b/build/engine/sounds/actor/step/tin1.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..3f46493f0495972c6dd575da3965a4dc40cc7103
Binary files /dev/null and b/build/engine/sounds/actor/step/tin1.ogg differ
diff --git a/build/engine/sounds/actor/step/tin2.ogg b/build/engine/sounds/actor/step/tin2.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..f24e21407c78a4cc3062e38d9f47e9f34edfb638
Binary files /dev/null and b/build/engine/sounds/actor/step/tin2.ogg differ
diff --git a/build/engine/sounds/actor/step/tin3.ogg b/build/engine/sounds/actor/step/tin3.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..29e734b64bec62da25d71e30a0fe33c7b0654eb2
Binary files /dev/null and b/build/engine/sounds/actor/step/tin3.ogg differ
diff --git a/build/engine/sounds/actor/step/tin4.ogg b/build/engine/sounds/actor/step/tin4.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..0939da1dedf474b6bed20e32b3b52f2de386fb89
Binary files /dev/null and b/build/engine/sounds/actor/step/tin4.ogg differ
diff --git a/build/engine/sounds/actor/step/wpn_large1.ogg b/build/engine/sounds/actor/step/wpn_large1.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..6eaa45b21f4569f11addc776c38f26bf5b815b9d
Binary files /dev/null and b/build/engine/sounds/actor/step/wpn_large1.ogg differ
diff --git a/build/engine/sounds/actor/step/wpn_large2.ogg b/build/engine/sounds/actor/step/wpn_large2.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..acff58e339b5aa1897bd419a349909c0b466a496
Binary files /dev/null and b/build/engine/sounds/actor/step/wpn_large2.ogg differ
diff --git a/build/engine/sounds/actor/step/wpn_small1.ogg b/build/engine/sounds/actor/step/wpn_small1.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..7fdca9aa57ded3ee490280c575ae828f70887b4b
Binary files /dev/null and b/build/engine/sounds/actor/step/wpn_small1.ogg differ
diff --git a/build/engine/sounds/actor/step/wpn_small2.ogg b/build/engine/sounds/actor/step/wpn_small2.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..f960ee93b63f7a65179278c8da1fecda9cff536d
Binary files /dev/null and b/build/engine/sounds/actor/step/wpn_small2.ogg differ
diff --git a/proj/SkyXEngine/vs2013/SkyXEngine.sln b/proj/SkyXEngine/vs2013/SkyXEngine.sln
index 88198265392df05fdfa6e792f88097f191277951..78df0cfb6eb3a499f4809fd3df03a26959a9ff06 100644
--- a/proj/SkyXEngine/vs2013/SkyXEngine.sln
+++ b/proj/SkyXEngine/vs2013/SkyXEngine.sln
@@ -15,6 +15,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SkyXEngine", "SkyXEngine.vc
 		{709D8A7A-D3E0-4070-A493-EFDF7A8E9D73} = {709D8A7A-D3E0-4070-A493-EFDF7A8E9D73}
 		{16D78A7B-8EE9-4FD3-84C9-B71D8723E718} = {16D78A7B-8EE9-4FD3-84C9-B71D8723E718}
 		{6A402480-C09B-4CBF-A6BD-115CE4BFF2D8} = {6A402480-C09B-4CBF-A6BD-115CE4BFF2D8}
+		{4A77FC81-98F6-4ABF-A489-B6F427354E5B} = {4A77FC81-98F6-4ABF-A489-B6F427354E5B}
 		{2B3BA583-D5EC-4DC2-91CF-42B1C7ADFD9D} = {2B3BA583-D5EC-4DC2-91CF-42B1C7ADFD9D}
 		{5145958A-F75F-4F6D-9793-7384B616CF76} = {5145958A-F75F-4F6D-9793-7384B616CF76}
 		{3A5449A3-DCE7-4557-9C9F-DEEAFBAAC763} = {3A5449A3-DCE7-4557-9C9F-DEEAFBAAC763}
@@ -362,6 +363,18 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "oggplugin", "..\..\oggplugi
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wavplugin", "..\..\wavplugin\vs2013\wavplugin.vcxproj", "{3DB7AC42-6141-417D-B2E6-7D62F08A2246}"
 EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xSound", "..\..\xSound\vs2013\xSound.vcxproj", "{4A77FC81-98F6-4ABF-A489-B6F427354E5B}"
+	ProjectSection(ProjectDependencies) = postProject
+		{3DB7AC42-6141-417D-B2E6-7D62F08A2246} = {3DB7AC42-6141-417D-B2E6-7D62F08A2246}
+		{C1C1F046-C839-4602-AF70-923CDD237C1B} = {C1C1F046-C839-4602-AF70-923CDD237C1B}
+		{8D0540EE-F8A5-44AB-8023-AD75251167E4} = {8D0540EE-F8A5-44AB-8023-AD75251167E4}
+		{F926F7FA-099E-499C-ABC9-743BCAB919C4} = {F926F7FA-099E-499C-ABC9-743BCAB919C4}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mital", "..\..\..\sdks\mital\proj\vs2013\mital\mital.vcxproj", "{8D0540EE-F8A5-44AB-8023-AD75251167E4}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "xSound", "xSound", "{3B9DBCFA-CFB6-459D-BE24-2EECB2E3042C}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Mixed Platforms = Debug|Mixed Platforms
@@ -872,6 +885,7 @@ Global
 		{02E4C411-4802-4522-A2D6-00094A4CD14B}.Debug|Win32.ActiveCfg = Debug|Win32
 		{02E4C411-4802-4522-A2D6-00094A4CD14B}.Debug|Win32.Build.0 = Debug|Win32
 		{02E4C411-4802-4522-A2D6-00094A4CD14B}.Debug|x64.ActiveCfg = Debug|x64
+		{02E4C411-4802-4522-A2D6-00094A4CD14B}.Debug|x64.Build.0 = Debug|x64
 		{02E4C411-4802-4522-A2D6-00094A4CD14B}.Release|Mixed Platforms.ActiveCfg = Release|x64
 		{02E4C411-4802-4522-A2D6-00094A4CD14B}.Release|Mixed Platforms.Build.0 = Release|x64
 		{02E4C411-4802-4522-A2D6-00094A4CD14B}.Release|Win32.ActiveCfg = Release|Win32
@@ -882,6 +896,7 @@ Global
 		{F926F7FA-099E-499C-ABC9-743BCAB919C4}.Debug|Win32.ActiveCfg = Debug|Win32
 		{F926F7FA-099E-499C-ABC9-743BCAB919C4}.Debug|Win32.Build.0 = Debug|Win32
 		{F926F7FA-099E-499C-ABC9-743BCAB919C4}.Debug|x64.ActiveCfg = Debug|x64
+		{F926F7FA-099E-499C-ABC9-743BCAB919C4}.Debug|x64.Build.0 = Debug|x64
 		{F926F7FA-099E-499C-ABC9-743BCAB919C4}.Release|Mixed Platforms.ActiveCfg = Release|Win32
 		{F926F7FA-099E-499C-ABC9-743BCAB919C4}.Release|Mixed Platforms.Build.0 = Release|Win32
 		{F926F7FA-099E-499C-ABC9-743BCAB919C4}.Release|Win32.ActiveCfg = Release|Win32
@@ -889,14 +904,40 @@ Global
 		{F926F7FA-099E-499C-ABC9-743BCAB919C4}.Release|x64.ActiveCfg = Release|x64
 		{3DB7AC42-6141-417D-B2E6-7D62F08A2246}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
 		{3DB7AC42-6141-417D-B2E6-7D62F08A2246}.Debug|Mixed Platforms.Build.0 = Debug|Win32
-		{3DB7AC42-6141-417D-B2E6-7D62F08A2246}.Debug|Win32.ActiveCfg = Debug|x64
-		{3DB7AC42-6141-417D-B2E6-7D62F08A2246}.Debug|Win32.Build.0 = Debug|x64
-		{3DB7AC42-6141-417D-B2E6-7D62F08A2246}.Debug|x64.ActiveCfg = Debug|Win32
+		{3DB7AC42-6141-417D-B2E6-7D62F08A2246}.Debug|Win32.ActiveCfg = Debug|Win32
+		{3DB7AC42-6141-417D-B2E6-7D62F08A2246}.Debug|Win32.Build.0 = Debug|Win32
+		{3DB7AC42-6141-417D-B2E6-7D62F08A2246}.Debug|x64.ActiveCfg = Debug|x64
+		{3DB7AC42-6141-417D-B2E6-7D62F08A2246}.Debug|x64.Build.0 = Debug|x64
 		{3DB7AC42-6141-417D-B2E6-7D62F08A2246}.Release|Mixed Platforms.ActiveCfg = Release|Win32
 		{3DB7AC42-6141-417D-B2E6-7D62F08A2246}.Release|Mixed Platforms.Build.0 = Release|Win32
 		{3DB7AC42-6141-417D-B2E6-7D62F08A2246}.Release|Win32.ActiveCfg = Release|Win32
 		{3DB7AC42-6141-417D-B2E6-7D62F08A2246}.Release|Win32.Build.0 = Release|Win32
 		{3DB7AC42-6141-417D-B2E6-7D62F08A2246}.Release|x64.ActiveCfg = Release|x64
+		{3DB7AC42-6141-417D-B2E6-7D62F08A2246}.Release|x64.Build.0 = Release|x64
+		{4A77FC81-98F6-4ABF-A489-B6F427354E5B}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
+		{4A77FC81-98F6-4ABF-A489-B6F427354E5B}.Debug|Mixed Platforms.Build.0 = Debug|Win32
+		{4A77FC81-98F6-4ABF-A489-B6F427354E5B}.Debug|Win32.ActiveCfg = Debug|Win32
+		{4A77FC81-98F6-4ABF-A489-B6F427354E5B}.Debug|Win32.Build.0 = Debug|Win32
+		{4A77FC81-98F6-4ABF-A489-B6F427354E5B}.Debug|x64.ActiveCfg = Debug|x64
+		{4A77FC81-98F6-4ABF-A489-B6F427354E5B}.Debug|x64.Build.0 = Debug|x64
+		{4A77FC81-98F6-4ABF-A489-B6F427354E5B}.Release|Mixed Platforms.ActiveCfg = Release|Win32
+		{4A77FC81-98F6-4ABF-A489-B6F427354E5B}.Release|Mixed Platforms.Build.0 = Release|Win32
+		{4A77FC81-98F6-4ABF-A489-B6F427354E5B}.Release|Win32.ActiveCfg = Release|Win32
+		{4A77FC81-98F6-4ABF-A489-B6F427354E5B}.Release|Win32.Build.0 = Release|Win32
+		{4A77FC81-98F6-4ABF-A489-B6F427354E5B}.Release|x64.ActiveCfg = Release|x64
+		{4A77FC81-98F6-4ABF-A489-B6F427354E5B}.Release|x64.Build.0 = Release|x64
+		{8D0540EE-F8A5-44AB-8023-AD75251167E4}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
+		{8D0540EE-F8A5-44AB-8023-AD75251167E4}.Debug|Mixed Platforms.Build.0 = Debug|Win32
+		{8D0540EE-F8A5-44AB-8023-AD75251167E4}.Debug|Win32.ActiveCfg = Debug|Win32
+		{8D0540EE-F8A5-44AB-8023-AD75251167E4}.Debug|Win32.Build.0 = Debug|Win32
+		{8D0540EE-F8A5-44AB-8023-AD75251167E4}.Debug|x64.ActiveCfg = Debug|x64
+		{8D0540EE-F8A5-44AB-8023-AD75251167E4}.Debug|x64.Build.0 = Debug|x64
+		{8D0540EE-F8A5-44AB-8023-AD75251167E4}.Release|Mixed Platforms.ActiveCfg = Release|Win32
+		{8D0540EE-F8A5-44AB-8023-AD75251167E4}.Release|Mixed Platforms.Build.0 = Release|Win32
+		{8D0540EE-F8A5-44AB-8023-AD75251167E4}.Release|Win32.ActiveCfg = Release|Win32
+		{8D0540EE-F8A5-44AB-8023-AD75251167E4}.Release|Win32.Build.0 = Release|Win32
+		{8D0540EE-F8A5-44AB-8023-AD75251167E4}.Release|x64.ActiveCfg = Release|x64
+		{8D0540EE-F8A5-44AB-8023-AD75251167E4}.Release|x64.Build.0 = Release|x64
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
@@ -961,5 +1002,8 @@ Global
 		{02E4C411-4802-4522-A2D6-00094A4CD14B} = {602837DA-C6C8-4D51-97A1-770224A52693}
 		{F926F7FA-099E-499C-ABC9-743BCAB919C4} = {602837DA-C6C8-4D51-97A1-770224A52693}
 		{3DB7AC42-6141-417D-B2E6-7D62F08A2246} = {7C1F0E50-7A19-4AB4-B559-11EF078F4787}
+		{4A77FC81-98F6-4ABF-A489-B6F427354E5B} = {3B9DBCFA-CFB6-459D-BE24-2EECB2E3042C}
+		{8D0540EE-F8A5-44AB-8023-AD75251167E4} = {3B9DBCFA-CFB6-459D-BE24-2EECB2E3042C}
+		{3B9DBCFA-CFB6-459D-BE24-2EECB2E3042C} = {4408F4BE-1F9D-4861-881A-AF9869C3D663}
 	EndGlobalSection
 EndGlobal
diff --git a/proj/oggplugin/vs2013/oggplugin.vcxproj b/proj/oggplugin/vs2013/oggplugin.vcxproj
index a484c17e8ee1f38046bbd39081643b01c5e798be..8a51092afe8f54308d9774c70e59123f2a31bd31 100644
--- a/proj/oggplugin/vs2013/oggplugin.vcxproj
+++ b/proj/oggplugin/vs2013/oggplugin.vcxproj
@@ -98,7 +98,7 @@
       </PrecompiledHeader>
       <WarningLevel>Level3</WarningLevel>
       <Optimization>Disabled</Optimization>
-      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;OGGPLUGIN_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;OGGPLUGIN_EXPORTS;SX_LIB_NAME="OGG";%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
     </ClCompile>
     <Link>
@@ -114,7 +114,7 @@
       </PrecompiledHeader>
       <WarningLevel>Level3</WarningLevel>
       <Optimization>Disabled</Optimization>
-      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;OGGPLUGIN_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;OGGPLUGIN_EXPORTS;SX_LIB_NAME="OGG";%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
     </ClCompile>
     <Link>
@@ -132,7 +132,7 @@
       <Optimization>MaxSpeed</Optimization>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
-      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;OGGPLUGIN_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;OGGPLUGIN_EXPORTS;SX_LIB_NAME="OGG";%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
     </ClCompile>
     <Link>
@@ -152,7 +152,7 @@
       <Optimization>MaxSpeed</Optimization>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
-      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;OGGPLUGIN_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;OGGPLUGIN_EXPORTS;SX_LIB_NAME="OGG";%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
     </ClCompile>
     <Link>
diff --git a/proj/sxgame/vs2013/sxgame.vcxproj b/proj/sxgame/vs2013/sxgame.vcxproj
index 68c8350f5c9ecd251f00065532e92a422c0bcefa..a867ed7d5d6d21a2bac09eec943028b698ef42e8 100644
--- a/proj/sxgame/vs2013/sxgame.vcxproj
+++ b/proj/sxgame/vs2013/sxgame.vcxproj
@@ -230,6 +230,7 @@
     <ClCompile Include="..\..\..\source\game\BaseTool.cpp" />
     <ClCompile Include="..\..\..\source\game\BaseWeapon.cpp" />
     <ClCompile Include="..\..\..\source\game\SettingsWriter.cpp" />
+    <ClCompile Include="..\..\..\source\game\SoundPlayer.cpp" />
     <ClCompile Include="..\..\..\source\game\sxgame_dll.cpp" />
     <ClCompile Include="..\..\..\source\game\Player.cpp" />
     <ClCompile Include="..\..\..\source\game\PlayerSpawn.cpp" />
@@ -296,6 +297,7 @@
     <ClInclude Include="..\..\..\source\game\BaseTool.h" />
     <ClInclude Include="..\..\..\source\game\BaseWeapon.h" />
     <ClInclude Include="..\..\..\source\game\SettingsWriter.h" />
+    <ClInclude Include="..\..\..\source\game\SoundPlayer.h" />
     <ClInclude Include="..\..\..\source\game\sxgame.h" />
     <ClInclude Include="..\..\..\source\game\Player.h" />
     <ClInclude Include="..\..\..\source\game\PlayerSpawn.h" />
diff --git a/proj/sxgame/vs2013/sxgame.vcxproj.filters b/proj/sxgame/vs2013/sxgame.vcxproj.filters
index 14e94410a9924cfda60a057cba1fc8cae9f108fa..71f76362f986dc8aadad08bdd70e8444ce6fbbf2 100644
--- a/proj/sxgame/vs2013/sxgame.vcxproj.filters
+++ b/proj/sxgame/vs2013/sxgame.vcxproj.filters
@@ -267,6 +267,9 @@
     <ClCompile Include="..\..\..\source\game\FuncTrain.cpp">
       <Filter>Source Files\ents\func</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\..\source\game\SoundPlayer.cpp">
+      <Filter>Header Files\ents</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\..\source\game\sxgame.h">
@@ -464,5 +467,8 @@
     <ClInclude Include="..\..\..\source\game\FuncTrain.h">
       <Filter>Header Files\ents\func</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\..\source\game\SoundPlayer.h">
+      <Filter>Header Files\ents</Filter>
+    </ClInclude>
   </ItemGroup>
 </Project>
\ No newline at end of file
diff --git a/proj/wavplugin/vs2013/wavplugin.vcxproj b/proj/wavplugin/vs2013/wavplugin.vcxproj
index 596d94b967382dff5d945be64717b699d5392719..eaa6250f062cd0b8851d34bfc0f0fe0ff049f5bd 100644
--- a/proj/wavplugin/vs2013/wavplugin.vcxproj
+++ b/proj/wavplugin/vs2013/wavplugin.vcxproj
@@ -94,7 +94,7 @@
       </PrecompiledHeader>
       <WarningLevel>Level3</WarningLevel>
       <Optimization>Disabled</Optimization>
-      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;WAVPLUGIN_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;WAVPLUGIN_EXPORTS;SX_LIB_NAME="WAV";%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
     </ClCompile>
     <Link>
@@ -110,7 +110,7 @@
       </PrecompiledHeader>
       <WarningLevel>Level3</WarningLevel>
       <Optimization>Disabled</Optimization>
-      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;WAVPLUGIN_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;WAVPLUGIN_EXPORTS;SX_LIB_NAME="WAV";%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
     </ClCompile>
     <Link>
@@ -128,7 +128,7 @@
       <Optimization>MaxSpeed</Optimization>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
-      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;WAVPLUGIN_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;WAVPLUGIN_EXPORTS;SX_LIB_NAME="WAV";%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
     </ClCompile>
     <Link>
@@ -148,7 +148,7 @@
       <Optimization>MaxSpeed</Optimization>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
-      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;WAVPLUGIN_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;WAVPLUGIN_EXPORTS;SX_LIB_NAME="WAV";%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
     </ClCompile>
     <Link>
diff --git a/proj/xSound/vs2013/xSound.vcxproj b/proj/xSound/vs2013/xSound.vcxproj
new file mode 100644
index 0000000000000000000000000000000000000000..2c29048701da7f6a0e105fbe93654c78fda3fc6d
--- /dev/null
+++ b/proj/xSound/vs2013/xSound.vcxproj
@@ -0,0 +1,190 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{4A77FC81-98F6-4ABF-A489-B6F427354E5B}</ProjectGuid>
+    <Keyword>Win32Proj</Keyword>
+    <RootNamespace>xSound</RootNamespace>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v120</PlatformToolset>
+    <CharacterSet>MultiByte</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v120</PlatformToolset>
+    <CharacterSet>MultiByte</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v120</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>MultiByte</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v120</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>MultiByte</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <LinkIncremental>false</LinkIncremental>
+    <IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);../../../sdks/;../../../source;../../../sdks/mital/source/;</IncludePath>
+    <OutDir>../../../build/bin/plugins/</OutDir>
+    <TargetName>$(ProjectName)_d</TargetName>
+    <LibraryPath>$(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86);../../../libs;../../../sdks/mital/lib/;</LibraryPath>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <TargetName>$(ProjectName)_d</TargetName>
+    <LibraryPath>$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);../../../libs64;../../../sdks/mital/lib64/;</LibraryPath>
+    <LinkIncremental>false</LinkIncremental>
+    <IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);../../../source;../../../sdks/mital/source/;../../../sdks/;</IncludePath>
+    <OutDir>../../../build/bin64/plugins/</OutDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <LinkIncremental>false</LinkIncremental>
+    <OutDir>../../../build/bin/plugins/</OutDir>
+    <IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);../../../sdks/;../../../source;../../../sdks/mital/source/;</IncludePath>
+    <LibraryPath>$(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86);../../../libs;../../../sdks/mital/lib/;</LibraryPath>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);../../../sdks/;../../../source;../../../sdks/mital/source/;</IncludePath>
+    <LibraryPath>$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);../../../libs64;../../../sdks/mital/lib64/;</LibraryPath>
+    <LinkIncremental>false</LinkIncremental>
+    <OutDir>../../../build/bin64/plugins/</OutDir>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;XSOUND_EXPORTS;SX_LIB_NAME="XSOUND";%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <ProgramDatabaseFile>$(ProjectDir)../../../pdb/$(TargetName).pdb</ProgramDatabaseFile>
+      <ImportLibrary>../../../libs/$(TargetName).lib</ImportLibrary>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;XSOUND_EXPORTS;SX_LIB_NAME="XSOUND";%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <ProgramDatabaseFile>$(ProjectDir)../../../pdb64/$(TargetName).pdb</ProgramDatabaseFile>
+      <ImportLibrary>../../../libs64/$(TargetName)_d.lib</ImportLibrary>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;XSOUND_EXPORTS;SX_LIB_NAME="XSOUND";%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <ImportLibrary>../../../libs/$(TargetName).lib</ImportLibrary>
+      <ProgramDatabaseFile>$(ProjectDir)../../../pdb/$(TargetName).pdb</ProgramDatabaseFile>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;XSOUND_EXPORTS;SX_LIB_NAME="XSOUND";%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <ImportLibrary>../../../libs64/$(TargetName).lib</ImportLibrary>
+      <ProgramDatabaseFile>$(ProjectDir)../../../pdb64/$(TargetName).pdb</ProgramDatabaseFile>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClCompile Include="..\..\..\source\xSound\dllmain.cpp" />
+    <ClCompile Include="..\..\..\source\xSound\plugin_main.cpp" />
+    <ClCompile Include="..\..\..\source\xSound\SoundBase.cpp" />
+    <ClCompile Include="..\..\..\source\xSound\SoundEmitter.cpp" />
+    <ClCompile Include="..\..\..\source\xSound\SoundLayer.cpp" />
+    <ClCompile Include="..\..\..\source\xSound\SoundLoader.cpp" />
+    <ClCompile Include="..\..\..\source\xSound\SoundPlayer.cpp" />
+    <ClCompile Include="..\..\..\source\xSound\SoundSystem.cpp" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="..\..\..\source\xSound\AudioConverter.h" />
+    <ClInclude Include="..\..\..\source\xSound\SoundBase.h" />
+    <ClInclude Include="..\..\..\source\xSound\SoundEmitter.h" />
+    <ClInclude Include="..\..\..\source\xSound\SoundLayer.h" />
+    <ClInclude Include="..\..\..\source\xSound\SoundLoader.h" />
+    <ClInclude Include="..\..\..\source\xSound\SoundPlayer.h" />
+    <ClInclude Include="..\..\..\source\xSound\SoundSystem.h" />
+    <ClInclude Include="..\..\..\source\xSound\SoundTypes.h" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>
\ No newline at end of file
diff --git a/proj/xSound/vs2013/xSound.vcxproj.filters b/proj/xSound/vs2013/xSound.vcxproj.filters
new file mode 100644
index 0000000000000000000000000000000000000000..1694219529c308d88f499888443c3faf4169f419
--- /dev/null
+++ b/proj/xSound/vs2013/xSound.vcxproj.filters
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="Source Files">
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+    </Filter>
+    <Filter Include="Header Files">
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+      <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
+    </Filter>
+    <Filter Include="Resource Files">
+      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="..\..\..\source\xSound\SoundSystem.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\..\source\xSound\dllmain.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\..\source\xSound\plugin_main.cpp" />
+    <ClCompile Include="..\..\..\source\xSound\SoundBase.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\..\source\xSound\SoundLayer.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\..\source\xSound\SoundPlayer.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\..\source\xSound\SoundEmitter.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\..\source\xSound\SoundLoader.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="..\..\..\source\xSound\SoundSystem.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\..\source\xSound\SoundBase.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\..\source\xSound\SoundLayer.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\..\source\xSound\SoundPlayer.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\..\source\xSound\SoundEmitter.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\..\source\xSound\AudioConverter.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\..\source\xSound\SoundLoader.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\..\source\xSound\SoundTypes.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+  </ItemGroup>
+</Project>
\ No newline at end of file
diff --git a/sdks/mital b/sdks/mital
index 41da9d03a8f00b8e8aec9f434e9bf9b33e589653..d0cbed91d28e1816044820a77902b37ed33b4596 160000
--- a/sdks/mital
+++ b/sdks/mital
@@ -1 +1 @@
-Subproject commit 41da9d03a8f00b8e8aec9f434e9bf9b33e589653
+Subproject commit d0cbed91d28e1816044820a77902b37ed33b4596
diff --git a/source/anim/DynamicModelProvider.cpp b/source/anim/DynamicModelProvider.cpp
index 3826ab7d5366efcc526e764a4db09207ef06bf25..ac4ca03a5a0d3e42b65f3ba25949924746f6fe86 100644
--- a/source/anim/DynamicModelProvider.cpp
+++ b/source/anim/DynamicModelProvider.cpp
@@ -188,8 +188,6 @@ CDynamicModelProvider::~CDynamicModelProvider()
 	mem_release(m_pOpaqueQuery);
 	mem_release(m_pTransparentQuery);
 	mem_release(m_pSelfillumQuery);
-	mem_release(m_pObjectType);
-	mem_release(m_pScene);
 }
 
 IGXVertexDeclaration *CDynamicModelProvider::getVertexDeclaration()
diff --git a/source/core/ResourceManager.cpp b/source/core/ResourceManager.cpp
index 8c2dbfb016ebcb8ea6496a6842d8b20809df669b..8a07980a2eba96de5df742df5e0b379edb79100b 100644
--- a/source/core/ResourceManager.cpp
+++ b/source/core/ResourceManager.cpp
@@ -11,6 +11,7 @@
 #include <xcommon/resource/IXModelProvider.h>
 #include <xcommon/resource/IXResourceManager.h>
 #include <xcommon/resource/IXResourceModel.h>
+#include <xcommon/IXAudioCodec.h>
 #endif
 
 
@@ -65,6 +66,28 @@ CResourceManager::CResourceManager(IXCore *pCore):
 			}
 		}
 	}
+
+	{
+		IXAudioCodec *pAudioCodec;
+		UINT ic = 0;
+		while ((pAudioCodec = (IXAudioCodec*)pPluginManager->getInterface(IXAUDIOCODEC_GUID, ic++)))
+		{
+			if (pAudioCodec->getVersion() == IXAUDIOCODEC_VERSION)
+			{
+				//LibReport(REPORT_MSG_LEVEL_NOTICE, "Registered sound loader:\n %s\n By %s\n %s\n", pAudioCodec->getDescription(), pAudioCodec->getAuthor(), pAudioCodec->getCopyright());
+
+				for (UINT i = 0, l = pAudioCodec->getExtCount(); i < l; ++i)
+				{
+					AAString sExt;
+					sExt.setName(pAudioCodec->getExt(i));
+					strlwr(const_cast<char*>(sExt.getName()));
+					m_aSoundExts.push_back({ pAudioCodec->getExt(i), pAudioCodec->getExt(i) });
+					LibReport(REPORT_MSG_LEVEL_NOTICE, " Ext: " COLOR_LCYAN "%s" COLOR_RESET ": " COLOR_WHITE "%s" COLOR_RESET "\n", pAudioCodec->getExt(i), pAudioCodec->getExt(i));
+				}
+				LibReport(REPORT_MSG_LEVEL_NOTICE, " \n");
+			}
+		}
+	}
 }
 
 bool XMETHODCALLTYPE CResourceManager::getModel(const char *szName, IXResourceModel **ppOut, bool bForceReload)
@@ -339,7 +362,21 @@ void XMETHODCALLTYPE CResourceManager::addModel(const char *szName, IXResourceMo
 	pResource->setFileName(m_mpModels.TmpNode->Key.c_str());
 }
 
+//##########################################################################
+
+UINT XMETHODCALLTYPE CResourceManager::getSoundSupportedFormats()
+{
+	return(m_aSoundExts.size());
+}
+
+const XFormatName* XMETHODCALLTYPE CResourceManager::getSoundSupportedFormat(UINT uIndex)
+{
+	assert(uIndex < m_aSoundExts.size());
+
+	return(&m_aSoundExts[uIndex]);
+}
 
+//##########################################################################
 
 
 
diff --git a/source/core/ResourceManager.h b/source/core/ResourceManager.h
index 26da34a11c3afae9a7507bd9cb3046343e5bd92c..de08f5a2960beb18786363ef807387451d05b83d 100644
--- a/source/core/ResourceManager.h
+++ b/source/core/ResourceManager.h
@@ -54,6 +54,9 @@ public:
 		}
 	}
 
+	UINT XMETHODCALLTYPE getSoundSupportedFormats() override;
+	const XFormatName* XMETHODCALLTYPE getSoundSupportedFormat(UINT uIndex) override;
+
 protected:
 	IXCore *m_pCore;
 
@@ -69,6 +72,8 @@ protected:
 	Array<XFormatName> m_aTextureExts;
 
 	const char* getExtension(const char *szName);
+
+	Array<XFormatName> m_aSoundExts;
 };
 
 #endif
diff --git a/source/game/GameData.cpp b/source/game/GameData.cpp
index f311d9e6ca6622a0f09ba897b1c91654bafab347..bb38523c4041be8ab4366d66a3a01bb3704db9d4 100644
--- a/source/game/GameData.cpp
+++ b/source/game/GameData.cpp
@@ -1190,8 +1190,10 @@ GameData::~GameData()
 
 	for(int i = 0; i < MPT_COUNT; ++i)
 	{
-		// @TODO: SSCore_SndDelete3dInst()
-		mem_delete_a(m_pidFootstepSound[i]);
+		int iCount = m_iFootstepSoundCount[i];
+		for (int j = 0; j < iCount; ++j)
+			mem_release(m_aFootstepSound[i][j]);
+		mem_delete_a(m_aFootstepSound[i]);
 	}
 }
 
@@ -1401,55 +1403,65 @@ void GameData::playFootstepSound(MTLTYPE_PHYSIC mtl_type, const float3 &f3Pos)
 	{
 		return;
 	}
-	ID idSound = m_pidFootstepSound[mtl_type][rand() % iCount];
-	SSCore_SndInstancePlay3d(idSound, false, false, (float3*)&f3Pos);
+	/*ID idSound = m_pidFootstepSound[mtl_type][rand() % iCount];
+	SSCore_SndInstancePlay3d(idSound, false, false, (float3*)&f3Pos);*/
+	IXSoundEmitter *pEmitter = m_aFootstepSound[mtl_type][rand() % iCount];
+	if (pEmitter)
+		pEmitter->play();
 }
 
 void GameData::loadFoostepsSounds()
 {
 	Array<const char*> aSounds[MPT_COUNT];
 
-	aSounds[MTLTYPE_PHYSIC_CONCRETE].push_back("actor/step/default1.ogg");
-	aSounds[MTLTYPE_PHYSIC_CONCRETE].push_back("actor/step/default2.ogg");
-	aSounds[MTLTYPE_PHYSIC_CONCRETE].push_back("actor/step/default3.ogg");
-	aSounds[MTLTYPE_PHYSIC_CONCRETE].push_back("actor/step/default4.ogg");
+	aSounds[MTLTYPE_PHYSIC_CONCRETE].push_back("sounds/actor/step/default1.ogg");
+	aSounds[MTLTYPE_PHYSIC_CONCRETE].push_back("sounds/actor/step/default2.ogg");
+	aSounds[MTLTYPE_PHYSIC_CONCRETE].push_back("sounds/actor/step/default3.ogg");
+	aSounds[MTLTYPE_PHYSIC_CONCRETE].push_back("sounds/actor/step/default4.ogg");
 
-	aSounds[MTLTYPE_PHYSIC_METAL].push_back("actor/step/metal_plate1.ogg");
-	aSounds[MTLTYPE_PHYSIC_METAL].push_back("actor/step/metal_plate2.ogg");
-	aSounds[MTLTYPE_PHYSIC_METAL].push_back("actor/step/metal_plate3.ogg");
-	aSounds[MTLTYPE_PHYSIC_METAL].push_back("actor/step/metal_plate4.ogg");
+	aSounds[MTLTYPE_PHYSIC_METAL].push_back("sounds/actor/step/metal_plate1.ogg");
+	aSounds[MTLTYPE_PHYSIC_METAL].push_back("sounds/actor/step/metal_plate2.ogg");
+	aSounds[MTLTYPE_PHYSIC_METAL].push_back("sounds/actor/step/metal_plate3.ogg");
+	aSounds[MTLTYPE_PHYSIC_METAL].push_back("sounds/actor/step/metal_plate4.ogg");
 
-	aSounds[MTLTYPE_PHYSIC_TREE].push_back("actor/step/new_wood1.ogg");
-	aSounds[MTLTYPE_PHYSIC_TREE].push_back("actor/step/new_wood2.ogg");
-	aSounds[MTLTYPE_PHYSIC_TREE].push_back("actor/step/new_wood3.ogg");
-	aSounds[MTLTYPE_PHYSIC_TREE].push_back("actor/step/new_wood4.ogg");
+	aSounds[MTLTYPE_PHYSIC_TREE].push_back("sounds/actor/step/new_wood1.ogg");
+	aSounds[MTLTYPE_PHYSIC_TREE].push_back("sounds/actor/step/new_wood2.ogg");
+	aSounds[MTLTYPE_PHYSIC_TREE].push_back("sounds/actor/step/new_wood3.ogg");
+	aSounds[MTLTYPE_PHYSIC_TREE].push_back("sounds/actor/step/new_wood4.ogg");
 
-	aSounds[MTLTYPE_PHYSIC_GROUD_SAND].push_back("actor/step/earth1.ogg");
-	aSounds[MTLTYPE_PHYSIC_GROUD_SAND].push_back("actor/step/earth2.ogg");
-	aSounds[MTLTYPE_PHYSIC_GROUD_SAND].push_back("actor/step/earth3.ogg");
-	aSounds[MTLTYPE_PHYSIC_GROUD_SAND].push_back("actor/step/earth4.ogg");
+	aSounds[MTLTYPE_PHYSIC_GROUD_SAND].push_back("sounds/actor/step/earth1.ogg");
+	aSounds[MTLTYPE_PHYSIC_GROUD_SAND].push_back("sounds/actor/step/earth2.ogg");
+	aSounds[MTLTYPE_PHYSIC_GROUD_SAND].push_back("sounds/actor/step/earth3.ogg");
+	aSounds[MTLTYPE_PHYSIC_GROUD_SAND].push_back("sounds/actor/step/earth4.ogg");
 
-	aSounds[MTLTYPE_PHYSIC_WATER].push_back("actor/step/t_water1.ogg");
-	aSounds[MTLTYPE_PHYSIC_WATER].push_back("actor/step/t_water2.ogg");
+	aSounds[MTLTYPE_PHYSIC_WATER].push_back("sounds/actor/step/t_water1.ogg");
+	aSounds[MTLTYPE_PHYSIC_WATER].push_back("sounds/actor/step/t_water2.ogg");
 
-	aSounds[MTLTYPE_PHYSIC_LEAF_GRASS].push_back("actor/step/grass1.ogg");
-	aSounds[MTLTYPE_PHYSIC_LEAF_GRASS].push_back("actor/step/grass2.ogg");
-	aSounds[MTLTYPE_PHYSIC_LEAF_GRASS].push_back("actor/step/grass3.ogg");
-	aSounds[MTLTYPE_PHYSIC_LEAF_GRASS].push_back("actor/step/grass4.ogg");
+	aSounds[MTLTYPE_PHYSIC_LEAF_GRASS].push_back("sounds/actor/step/grass1.ogg");
+	aSounds[MTLTYPE_PHYSIC_LEAF_GRASS].push_back("sounds/actor/step/grass2.ogg");
+	aSounds[MTLTYPE_PHYSIC_LEAF_GRASS].push_back("sounds/actor/step/grass3.ogg");
+	aSounds[MTLTYPE_PHYSIC_LEAF_GRASS].push_back("sounds/actor/step/grass4.ogg");
 
 	//aSounds[MTLTYPE_PHYSIC_GLASS].push_back("actor/step/.ogg");
 	//aSounds[MTLTYPE_PHYSIC_PLASTIC].push_back("actor/step/.ogg");
 	//aSounds[MTLTYPE_PHYSIC_FLESH].push_back("actor/step/.ogg");
 
+	IXSoundSystem *pSound = (IXSoundSystem*)(Core_GetIXCore()->getPluginManager()->getInterface(IXSOUNDSYSTEM_GUID));
+	IXSoundLayer *pMasterLayer = pSound->findLayer("master");
+
+	if (!pMasterLayer)
+		return;
+
 	for(int i = 0; i < MPT_COUNT; ++i)
 	{
 		Array<const char*> *paSounds = &aSounds[i];
 		int jl = paSounds->size();
 		m_iFootstepSoundCount[i] = jl;
-		m_pidFootstepSound[i] = jl ? new ID[jl] : NULL;
+		m_aFootstepSound[i] = (jl ? new IXSoundEmitter*[jl] : NULL);
 		for(int j = 0; j < jl; ++j)
 		{
-			m_pidFootstepSound[i][j] = SSCore_SndCreate3dInst(paSounds[0][j], SX_SOUND_CHANNEL_GAME, 100);
+			m_aFootstepSound[i][j] = pMasterLayer->newSoundEmitter(paSounds[0][j], SOUND_DTYPE_3D);
+			//m_aFootstepSound[i][j] = SSCore_SndCreate3dInst(paSounds[0][j], SX_SOUND_CHANNEL_GAME, 100);
 		}
 	}
 }
diff --git a/source/game/GameData.h b/source/game/GameData.h
index 3a858aebeb01d7bde4d052e60d3bd2e80d0d2dc2..af9f47b8620dcc90182420f9613d5d97b358b839 100644
--- a/source/game/GameData.h
+++ b/source/game/GameData.h
@@ -15,6 +15,7 @@ See the license in LICENSE
 #include "HUDcontroller.h"
 #include "GameStateManager.h"
 #include <light/IXLightSystem.h>
+#include <xcommon/IXSoundSystem.h>
 
 class GameData
 {
@@ -50,7 +51,8 @@ protected:
 
 	void loadFoostepsSounds();
 
-	ID *m_pidFootstepSound[MPT_COUNT];
+	//ID *m_pidFootstepSound[MPT_COUNT];
+	IXSoundEmitter **m_aFootstepSound[MPT_COUNT];
 	int m_iFootstepSoundCount[MPT_COUNT];
 
 	static void ccmd_forward_on();
diff --git a/source/game/SoundPlayer.cpp b/source/game/SoundPlayer.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..17491fd4a92b613ae4c3d1a46b2112ad277c320e
--- /dev/null
+++ b/source/game/SoundPlayer.cpp
@@ -0,0 +1,47 @@
+
+#include "SoundPlayer.h"
+
+/*! \skydocent sound_player
+	
+*/
+
+BEGIN_PROPTABLE(CSoundPlayer)
+
+DEFINE_FIELD_STRINGFN(m_szPathSound, 0, "file", "Sound file", setSound, EDITOR_SOUND)
+
+DEFINE_FIELD_FLOAT(m_fDist, 0, "distance", "Hearing distance", EDITOR_TEXTFIELD)
+
+END_PROPTABLE()
+
+REGISTER_ENTITY(CSoundPlayer, sound_player);
+
+//##########################################################################
+
+CSoundPlayer::CSoundPlayer(CEntityManager *pMgr):
+	BaseClass(pMgr),
+	m_pPlayer(NULL)
+{
+	
+}
+
+void CSoundPlayer::setSound(const char *szSound)
+{
+	mem_release(m_pPlayer);
+	IXSoundSystem *pSound = (IXSoundSystem*)(Core_GetIXCore()->getPluginManager()->getInterface(IXSOUNDSYSTEM_GUID));
+	IXSoundLayer *pMasterLayer = pSound->findLayer("master");
+	m_pPlayer = pMasterLayer->newSoundPlayer(szSound, SOUND_DTYPE_3D);
+	if (m_pPlayer)
+	{
+		m_pPlayer->setLoop(SOUND_LOOP_SIMPLE);
+		m_pPlayer->play();
+	}
+}
+
+void CSoundPlayer::onSync()
+{
+	if (!m_pPlayer)
+		return;
+
+	float3 vPos = getPos();
+	m_pPlayer->setWorldPos(vPos);
+}
\ No newline at end of file
diff --git a/source/game/SoundPlayer.h b/source/game/SoundPlayer.h
new file mode 100644
index 0000000000000000000000000000000000000000..58d463da065e65c05d0d3bd4053c4aeed2fb3744
--- /dev/null
+++ b/source/game/SoundPlayer.h
@@ -0,0 +1,45 @@
+/*****************************************************
+Copyright � DogmaNet Team, 2020
+Site: dogmanet.ru
+See the license in LICENSE
+*****************************************************/
+
+/*!
+	\file
+	����� ��������� ������
+*/
+#ifndef __SOUND_PLAYER_H
+#define __SOUND_PLAYER_H
+
+#include "PointEntity.h"
+#include <xcommon/IXSoundSystem.h>
+
+
+/*! ����� ��������� ������
+	\ingroup cpointentity
+*/
+class CSoundPlayer : public CPointEntity
+{
+	DECLARE_CLASS(CSoundPlayer, CPointEntity);
+	DECLARE_PROPTABLE();
+public:
+	//CSoundPlayer() = default;
+	CSoundPlayer(CEntityManager * pMgr);
+
+	virtual void setSound(const char *szSound);
+
+	void onSync() override;
+
+	void stop();
+	
+	void play();
+
+protected:
+	
+	IXSoundPlayer *m_pPlayer = NULL;
+	const char *m_szPathSound = "";
+
+	float m_fDist = 10.f;
+};
+
+#endif
diff --git a/source/game/proptable.h b/source/game/proptable.h
index 4f18c2f55b9fac0c9d8bc3c3e7646d0bcc4acb01..b59a1e2c4c7e75c0cfd95b4736a68d2ce43060a6 100644
--- a/source/game/proptable.h
+++ b/source/game/proptable.h
@@ -397,6 +397,7 @@ const char * GetEmptyString();
 
 #define EDITOR_YESNO EDITOR_COMBOBOX COMBO_OPTION("Yes", "1") COMBO_OPTION("No", "0") EDITOR_COMBO_END()
 #define EDITOR_MODEL EDITOR_FILEFIELD FILE_OPTION("Select model", "dse") EDITOR_FILE_END()
+#define EDITOR_SOUND EDITOR_FILEFIELD FILE_OPTION("Select sound", "ogg") EDITOR_FILE_END()
 
 #define DEFINE_FIELD_STRING(field, flags, keyname, edname, editor)              , {propdata_t::ToFieldType<const char* DataClass::*>(&DataClass::field),  PDF_STRING,  flags, keyname, edname, NULL,                                     editor
 #define DEFINE_FIELD_VECTOR(field, flags, keyname, edname, editor)              , {propdata_t::ToFieldType<float3_t DataClass::*>(&DataClass::field),     PDF_VECTOR,  flags, keyname, edname, NULL,                                     editor
diff --git a/source/oggplugin/AudioCodecOgg.cpp b/source/oggplugin/AudioCodecOgg.cpp
index 749bcb6dea315fc820755b76aee69e1542903f8d..8e1085b657a51facec6ec9dc0c7244af54b53239 100644
--- a/source/oggplugin/AudioCodecOgg.cpp
+++ b/source/oggplugin/AudioCodecOgg.cpp
@@ -3,44 +3,75 @@
 
 //##########################################################################
 
-size_t OggCallbackRead(void *ptr, size_t size, size_t nmemb, void *datasource)
+size_t OggCallbackRead(void *pDataDest, size_t size, size_t nmemb, void *pDataFile)
 {
-	FILE* f = (FILE*)datasource;
-	return fread(ptr, 1, size * nmemb, f);
+	IFile *pFile = (IFile*)pDataFile;
+	return pFile->readBin(pDataDest, size * nmemb);
 }
 
-int OggCallbackClose(void* datasource)
+//**************************************************************************
+
+int OggCallbackClose(void *pDataFile)
 {
-	FILE* f = (FILE*)datasource;
-	fclose(f);
+	IFile *pFile = (IFile*)pDataFile;
+	//эту функци. вызывает ov_clear, но надо чтобы владалец обьекта сам закрывал файл
+	//mem_release(pFile);
 	return 0;
 }
 
-int OggCallbackSeek(void *datasource, ogg_int64_t offset, int whence)
+//**************************************************************************
+
+int OggCallbackSeek(void *pDataFile, ogg_int64_t offset, int whence)
 {
-	FILE* f = (FILE*)datasource;
+	IFile *pFile = (IFile*)pDataFile;
 	switch (whence)
 	{
-	case SEEK_SET: return fseek(f, offset, SEEK_SET);
-	case SEEK_CUR: return fseek(f, offset, SEEK_CUR);
-	case SEEK_END: return fseek(f, offset, SEEK_END);
-	default: return -1;
+	case SEEK_SET:
+	{
+		if (offset < 0 || offset > pFile->getSize())
+			return 1;
+		pFile->setPos(offset);
+		return 0;
+	}
+	case SEEK_CUR:
+	{
+		size_t uPos = pFile->getPos() + offset;
+		if (uPos < 0 || uPos > pFile->getSize())
+			return 1;
+
+		pFile->setPos(uPos);
+		return 0;
+	}
+	case SEEK_END:
+	{
+		size_t uPos = pFile->getSize() + offset;
+		if (uPos < 0 || uPos > pFile->getSize())
+			return 1;
+
+		pFile->setPos(uPos);
+		return 0;
+	}
+	default: 
+		return -1;
 	}
 	return 1;
 }
 
-long OggCallbackTell(void* datasource)
+//**************************************************************************
+
+long OggCallbackTell(void *pDataFile)
 {
-	FILE* f = (FILE*)datasource;
-	return ftell(f);
+	IFile *pFile = (IFile*)pDataFile;
+	return pFile->getPos();
 }
 
 //##########################################################################
 //##########################################################################
 //##########################################################################
 
-CAudioCodecOgg::CAudioCodecOgg()
+CAudioCodecOgg::CAudioCodecOgg(IFileSystem *pFileSystem)
 {
+	m_pFileSystem = pFileSystem;
 	m_oCB.close_func = OggCallbackClose;
 	m_oCB.read_func = OggCallbackRead;
 	m_oCB.seek_func = OggCallbackSeek;
@@ -68,9 +99,9 @@ UINT XMETHODCALLTYPE CAudioCodecOgg::getExtCount() const
 
 bool XMETHODCALLTYPE CAudioCodecOgg::open(const char *szFile, const char *szArg, IXAudioCodecTarget **ppTarget, bool forSave)
 {
-	FILE *pFile = fopen(szFile, (forSave ? "wb" : "rb"));
+	IFile *pFile = m_pFileSystem->openFile(szFile, (forSave ? FILE_MODE_WRITE : FILE_MODE_READ));
 
-	if (!pFile || !ppTarget)
+	if (!pFile || !ppTarget || (forSave && (!szArg && strcasecmp(szArg, getFormat()) != 0)))
 		return false;
 
 	OggVorbis_File *pVoFile = NULL;
@@ -126,11 +157,13 @@ CAudioCodecTargetOgg::~CAudioCodecTargetOgg()
 		ov_clear(m_pVoFile);
 		mem_delete(m_pVoFile);
 	}
+
+	mem_release(m_pFile);
 }
 
 //**************************************************************************
 
-void CAudioCodecTargetOgg::init(FILE *pFile, OggVorbis_File *pVoFile, AudioRawDesc *pDesc, bool forSave)
+void CAudioCodecTargetOgg::init(IFile *pFile, OggVorbis_File *pVoFile, AudioRawDesc *pDesc, bool forSave)
 {
 	m_pFile = pFile;
 	m_pVoFile = pVoFile;
@@ -156,7 +189,7 @@ int64_t XMETHODCALLTYPE CAudioCodecTargetOgg::getPos() const
 	if (!m_pFile || !m_pVoFile)
 		return 0;
 
-	return ov_pcm_tell(m_pVoFile);
+	return ov_pcm_tell(m_pVoFile)*OGG_BYTES_PER_SAMPLE;
 }
 
 //**************************************************************************
@@ -166,7 +199,7 @@ void XMETHODCALLTYPE CAudioCodecTargetOgg::setPos(int64_t iPos)
 	if (!m_pFile || !m_pVoFile)
 		return;
 
-	ov_pcm_seek(m_pVoFile, iPos);
+	ov_pcm_seek(m_pVoFile, iPos / OGG_BYTES_PER_SAMPLE);
 }
 
 //**************************************************************************
@@ -251,16 +284,14 @@ bool XMETHODCALLTYPE CAudioCodecTargetOgg::encode(IXBuffer *pBufferPCM, AudioRaw
 
 	//инициализация кодировщика (статических данных) с переменным битрейтом (variable bitrate)
 	vorbis_info_init(&oVoInfo);
-	iRetCode = vorbis_encode_init_vbr(&oVoInfo, pOutDesc->u8Channels, pOutDesc->uSampleRate, 0.1);
+	if ((iRetCode = vorbis_encode_init_vbr(&oVoInfo, pOutDesc->u8Channels, pOutDesc->uSampleRate, 0.2)))
+		return false;
 
 	/* можно заюзать усредненный битрейт (average bitrate):
-	iRetCode = vorbis_encode_init(&vi,pOutDesc->u8Channels, pOutDesc->uSampleRate,-1,128000,-1);
-	 * но в данной реализации пусть кодировщик сам разбирается :)
+		iRetCode = vorbis_encode_init(&vi,pOutDesc->u8Channels, pOutDesc->uSampleRate,-1,128000,-1);
+		но в данной реализации пусть кодировщик сам разбирается :)
 	*/
 
-	if(iRetCode)
-		return false;
-
 	//инициализируем комментарий
 	vorbis_comment_init(&oVoComment);
 	vorbis_comment_add_tag(&oVoComment, "ENCODER", "SkyXEngine plugin [class 'codec_ogg']");
@@ -282,39 +313,50 @@ bool XMETHODCALLTYPE CAudioCodecTargetOgg::encode(IXBuffer *pBufferPCM, AudioRaw
 	//**************************************************
 	//сброс заголовков в логический поток данных
 
-	while(!iEndOfStream)
+	while (ogg_stream_flush(&oOggStream, &oOggPage))
 	{
-		iRetCode = ogg_stream_flush(&oOggStream, &oOggPage);
-		if(iRetCode == 0)
-			break;
-		fwrite(oOggPage.header, 1, oOggPage.header_len, m_pFile);
-		fwrite(oOggPage.body, 1, oOggPage.body_len, m_pFile);
+		m_pFile->writeBin(oOggPage.header, oOggPage.header_len);
+		m_pFile->writeBin(oOggPage.body, oOggPage.body_len);
 	}
 
 	//**************************************************
 	// инициализация семплов
 
+	
 	//количество блоков семплов (количество каналов * байт на семпл)
 	int iCountBlocks = uSize/ (pOutDesc->u8BlockAlign);
 
+	//по сколько блоков записывать за один раз
+	int iPartBlocks = 1024;
+
+	//количество уже записанных блоков
+	int iCountReadedBlocks = 0;
+
+	/*в общем процесс записи сэмлов выглядит как показано в закомментированном коде ниже
+		но так делать не надо, потому что внутри vorbis_analysis_wrote выделяется память на стеке по общему количеству блоков
+		это может привести к переполнению стека
+	*/
+	/* но разделять на блоки и передавать таким образом данные тоже нельзя
+	*/
 	/* получаем выделенный массив (по количеству каналов) массивов (по количеству семплов)
 		aaBuffer[iChannel][iSample]
 	*/
-	float **aaBuffer = vorbis_analysis_buffer(&oVoMainState, iCountBlocks);
+	/*float **aaBuffer = vorbis_analysis_buffer(&oVoMainState, iCountBlocks);
+	int iCurrSample = 0;
 
 	//заполняем выделенный float массив нормализованными данными [-1.0, 1.0]
 	for(int i = 0; i < iCountBlocks ; ++i)
 	{
 		for(int iChannels = 0; iChannels<pOutDesc->u8Channels; ++iChannels)
 		{
-			int16_t i16Sample = ((int16_t*)pData)[i];
-			aaBuffer[iChannels][i]=float(i16Sample)/32768.f;
+			iCurrSample = i * pOutDesc->u8Channels + iChannels;
+			int16_t i16Sample = ((int16_t*)pData)[iCurrSample];
+			aaBuffer[iChannels][i] = float(i16Sample) / 32768.f;
 		}
 	}
 
 	//сообщаем кодировщику что поступили данные для записи
-	vorbis_analysis_wrote(&oVoMainState, iCountBlocks);
-
+	vorbis_analysis_wrote(&oVoMainState, iCountBlocks);*/
 
 	//**************************************************
 	// запись семплов
@@ -322,34 +364,72 @@ bool XMETHODCALLTYPE CAudioCodecTargetOgg::encode(IXBuffer *pBufferPCM, AudioRaw
 	//если еще не дошли до конца битового потока, тогда продолжаем запись
 	while(!iEndOfStream)
 	{
-		/*разбивка несжатых данных на блоки, если не удалось, тогда сообщаем что данных больше не будет
-		 если не сообщить об этом, то не все данные будут записаны, не получится дойти до конца битового потока, потому что запись идет постраничная и последняя неполня страница не будет записана
-		*/
-		if(vorbis_analysis_blockout(&oVoMainState, &oVoDataBlock)!=1)
-			vorbis_analysis_wrote(&oVoMainState, 0);
+		//количество прочитанных семплов
+		uint32_t uCountReadedSamples = (iCountReadedBlocks*pOutDesc->u8Channels);
+		//количество блоков для текущей итерации
+		int iCurrBlocks = iPartBlocks;
+		if (iCountBlocks - iCountReadedBlocks < iPartBlocks)
+			iCurrBlocks = iCountBlocks - iCountReadedBlocks;
+
+		//если есть блоки для записи
+		if (iCurrBlocks > 0)
+		{
+			/* получаем выделенный массив (по количеству каналов) массивов (по количеству семплов)
+				aaBuffer[iChannel][iSample]
+			*/
+			float **aaBuffer = vorbis_analysis_buffer(&oVoMainState, iCurrBlocks);
+			int iCurrSample = 0;
+
+			//запись блоков
+			for (int i = 0; i < iCurrBlocks; ++i)
+			{
+				for (int iChannels = 0; iChannels < pOutDesc->u8Channels; ++iChannels)
+				{
+					iCurrSample = uCountReadedSamples + i * pOutDesc->u8Channels + iChannels;
+					int16_t i16Sample = ((int16_t*)pData)[iCurrSample];
+					aaBuffer[iChannels][i] = float(i16Sample) / 32768.f;
+				}
+			}
 
-		//поиск режима кодирования и отправка блока на кодировку
-		vorbis_analysis(&oVoDataBlock, NULL);
-		vorbis_bitrate_addblock(&oVoDataBlock);
+			//сообщаем кодировщику что поступили данные для записи
+			vorbis_analysis_wrote(&oVoMainState, iCurrBlocks);
+			iCountReadedBlocks += iCurrBlocks;
+		}
+		else
+		{
+			/* сообщаем что данных больше не будет
+				если не сообщить об этом, то не все данные будут записаны, не получится дойти до конца битового потока, 
+				потому что запись идет постраничная и последняя неполная страница не будет записана
+		 */
+			vorbis_analysis_wrote(&oVoMainState, 0);
+		}
 
-		//получение следующего доступного пакета
-		while(vorbis_bitrate_flushpacket(&oVoMainState, &oOggPacket))
+		while (vorbis_analysis_blockout(&oVoMainState, &oVoDataBlock) == 1)
 		{
-			//отправка пакета в битовый поток
-			ogg_stream_packetin(&oOggStream, &oOggPacket);
+			//поиск режима кодирования и отправка блока на кодировку
+			vorbis_analysis(&oVoDataBlock, NULL);
+			vorbis_bitrate_addblock(&oVoDataBlock);
 
-			while(!iEndOfStream)
+			//получение следующего доступного пакета
+			while (vorbis_bitrate_flushpacket(&oVoMainState, &oOggPacket))
 			{
-				//формирование пакетов в страницы и отправка в битовый поток
-				int result=ogg_stream_pageout(&oOggStream, &oOggPage);
-				if(result==0)
-					break;
-				fwrite(oOggPage.header, 1, oOggPage.header_len, m_pFile);
-				fwrite(oOggPage.body, 1, oOggPage.body_len, m_pFile);
-
-				//если все записано (находимся в конце битового потока), сообщаем о завершении
-				if(ogg_page_eos(&oOggPage))
-					iEndOfStream=1;
+				//отправка пакета в битовый поток
+				ogg_stream_packetin(&oOggStream, &oOggPacket);
+
+				while (!iEndOfStream)
+				{
+					//формирование пакетов в страницы и отправка в битовый поток
+					int result = ogg_stream_pageout(&oOggStream, &oOggPage);
+					if (result == 0)
+						break;
+
+					m_pFile->writeBin(oOggPage.header, oOggPage.header_len);
+					m_pFile->writeBin(oOggPage.body, oOggPage.body_len);
+
+					//если все записано (находимся в конце битового потока), сообщаем о завершении
+					if (ogg_page_eos(&oOggPage))
+						iEndOfStream = 1;
+				}
 			}
 		}
 	}
diff --git a/source/oggplugin/AudioCodecOgg.h b/source/oggplugin/AudioCodecOgg.h
index e1c46973dc8d553e8eb411ebcac7674a47666b80..727c5bd697be2c5e0045fb027bbfc23a1771a078 100644
--- a/source/oggplugin/AudioCodecOgg.h
+++ b/source/oggplugin/AudioCodecOgg.h
@@ -15,16 +15,22 @@ See the license in LICENSE
 
 #include <common/string.h>
 
+#include <xcommon/IFileSystem.h>
+#include <core/IFile.h>
+
 //! количество байт на семпл
 #define OGG_BYTES_PER_SAMPLE 2
 
+//##########################################################################
 
 class CAudioCodecOgg: public IXUnknownImplementation<IXAudioCodec>
 {
 public:
-	CAudioCodecOgg();
+	CAudioCodecOgg(IFileSystem *pFileSystem);
 	~CAudioCodecOgg(){}
 
+	XIMPLEMENT_VERSION(IXAUDIOCODEC_VERSION);
+
 	virtual const char* XMETHODCALLTYPE getFormat() const override;
 	virtual const char* XMETHODCALLTYPE getExt(UINT uIndex=0) const override;
 	virtual UINT XMETHODCALLTYPE getExtCount() const override;
@@ -34,6 +40,7 @@ public:
 protected:
 	ov_callbacks m_oCB;
 	Array<String> m_aExts;
+	IFileSystem *m_pFileSystem = NULL;
 };
 
 //##########################################################################
@@ -52,9 +59,9 @@ protected:
 
 	friend CAudioCodecOgg;
 
-	void init(FILE *pFile, OggVorbis_File *pVoFile, AudioRawDesc *pDesc, bool forSave);
+	void init(IFile *pFile, OggVorbis_File *pVoFile, AudioRawDesc *pDesc, bool forSave);
 
-	FILE *m_pFile = NULL;
+	IFile *m_pFile = NULL;
 	OggVorbis_File *m_pVoFile;
 	AudioRawDesc m_oDesc;
 	bool m_forSave = false;
diff --git a/source/oggplugin/plugin_main.cpp b/source/oggplugin/plugin_main.cpp
index 6b65fafa96b408bee5a3d02d3248278af90b460a..a9943aae09075c421bc7fceb3f7aadaa7d3a0cbe 100644
--- a/source/oggplugin/plugin_main.cpp
+++ b/source/oggplugin/plugin_main.cpp
@@ -20,6 +20,7 @@ class CAudioCodecOggPlugin: public IXUnknownImplementation<IXPlugin>
 public:
 	void XMETHODCALLTYPE startup(IXCore *pCore) override
 	{
+		m_pCore = pCore;
 	}
 
 	void XMETHODCALLTYPE shutdown() override
@@ -47,10 +48,13 @@ public:
 	{
 		if (guid == IXAUDIOCODEC_GUID)
 		{
-			return(new CAudioCodecOgg());
+			return(new CAudioCodecOgg(m_pCore->getFileSystem()));
 		}
 		return(NULL);
 	}
+
+protected:
+	IXCore *m_pCore = NULL;
 };
 
 DECLARE_XPLUGIN(CAudioCodecOggPlugin);
diff --git a/source/render/RenderPipeline.cpp b/source/render/RenderPipeline.cpp
index 16f67b33b154e589aa280d35c5e7ddafea0d8d79..30bbfdd1dc85cde1b8e4c8b3066e931a2c3349da 100644
--- a/source/render/RenderPipeline.cpp
+++ b/source/render/RenderPipeline.cpp
@@ -33,6 +33,8 @@ CRenderPipeline::CRenderPipeline(IGXDevice *pDevice):
 		{"vTexUV", GXDECLTYPE_FLOAT2, GXDECLUSAGE_TEXCOORD},
 		{"vNormal", GXDECLTYPE_FLOAT3, GXDECLUSAGE_TEXCOORD1},
 		{"vPos", GXDECLTYPE_FLOAT4, GXDECLUSAGE_TEXCOORD2},
+		{"vTangent", GXDECLTYPE_FLOAT3, GXDECLUSAGE_TEXCOORD3},
+		{"vBinormal", GXDECLTYPE_FLOAT3, GXDECLUSAGE_TEXCOORD4},
 		XVERTEX_OUTPUT_DECL_END()
 	};
 	XVertexFormatHandler *pVertexFormatSceneGeneric = m_pMaterialSystem->registerVertexFormat("xSceneGeneric", voelGeneric);
diff --git a/source/terrax/PropertyWindow.cpp b/source/terrax/PropertyWindow.cpp
index 76aa87e87df4ecdd158a8b9bb44fd3f3fb092559..f36b28edfb302a1bb3c03612eb42b2122a897858 100644
--- a/source/terrax/PropertyWindow.cpp
+++ b/source/terrax/PropertyWindow.cpp
@@ -353,11 +353,28 @@ INT_PTR CALLBACK CPropertyWindow::dlgProc(HWND hWnd, UINT msg, WPARAM wParam, LP
 			}
 			else if(!fstrcmp(szCurrentFileType, "sound"))
 			{
-				szTmp += swprintf(szTmp, L"All supported formats") + 1;
+				/*szTmp += swprintf(szTmp, L"All supported formats") + 1;
 				szTmp += swprintf(szTmp, L"*.ogg") + 1;
 
 				szTmp += swprintf(szTmp, L"Ogg Vorbis (*.ogg)") + 1;
-				szTmp += swprintf(szTmp, L"*.ogg") + 1;
+				szTmp += swprintf(szTmp, L"*.ogg") + 1;*/
+
+				auto pMgr = Core_GetIXCore()->getResourceManager();
+				UINT uFormatCount = pMgr->getSoundSupportedFormats();
+
+				szTmp += swprintf(szTmp, L"All supported formats") + 1;
+				for (UINT i = 0; i < uFormatCount; ++i)
+				{
+					auto pFmt = pMgr->getSoundSupportedFormat(i);
+					szTmp += swprintf(szTmp, L"*.%S;", pFmt->szExtension);
+				}
+				szTmp[-1] = 0;
+				for (UINT i = 0; i < uFormatCount; ++i)
+				{
+					auto pFmt = pMgr->getSoundSupportedFormat(i);
+					szTmp += swprintf(szTmp, L"%S (*.%S)", pFmt->szDescription, pFmt->szExtension) + 1;
+					szTmp += swprintf(szTmp, L"*.%S", pFmt->szExtension) + 1;
+				}
 			}
 			else
 			{
diff --git a/source/terrax/mainWindow.cpp b/source/terrax/mainWindow.cpp
index a7f9dfa4e2c0148f318443efc5db893acc56e728..2c15065db680632eac365235174123d8c5aba314 100644
--- a/source/terrax/mainWindow.cpp
+++ b/source/terrax/mainWindow.cpp
@@ -2182,6 +2182,10 @@ LRESULT CALLBACK RenderWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lP
 		DeleteObject(hcRotate);
 		break;
 
+	case WM_SETTITLEASYNC:
+		SetWindowTextA(hWnd, (LPCSTR)lParam);
+		break;
+
 	default:
 		return DefWindowProc(hWnd, message, wParam, lParam);
 	}
@@ -2276,7 +2280,7 @@ void XInitViewportLayout(X_VIEWPORT_LAYOUT layout)
 		break;
 	}
 	
-	SendMessage(g_hWndMain, WM_COMMAND, MAKEWPARAM(ID_VIEW_AUTOSIZEVIEWS, 0), 0);
+	PostMessage(g_hWndMain, WM_COMMAND, MAKEWPARAM(ID_VIEW_AUTOSIZEVIEWS, 0), 0);
 
 	g_xConfig.m_xViewportLayout = layout;
 	SetMenuItemInfoA(g_hMenu, uMenuId, FALSE, &mii);
diff --git a/source/terrax/terrax.cpp b/source/terrax/terrax.cpp
index c7eb03005ef91db34250c27d11a511b87f480879..88eca8c7a7a4a96170b96d477e33422db4dc64f5 100644
--- a/source/terrax/terrax.cpp
+++ b/source/terrax/terrax.cpp
@@ -1609,7 +1609,7 @@ bool XIsMouseInSelection(X_WINDOW_POS wnd)
 void XUpdateWindowTitle()
 {
 	const char *szLevelName = g_sLevelName.c_str();
-	char szCaption[256];
+	static char szCaption[256];
 	bool isDirty = g_pUndoManager->isDirty();
 	if(szLevelName && szLevelName[0])
 	{
@@ -1619,5 +1619,6 @@ void XUpdateWindowTitle()
 	{
 		sprintf(szCaption, "%s%s | %s", MAIN_WINDOW_TITLE, isDirty ? " - *" : "", SKYXENGINE_VERSION4EDITORS);
 	}
-	SetWindowText(g_hWndMain, szCaption);
+	PostMessageA(g_hWndMain, WM_SETTITLEASYNC, 0, (LPARAM)szCaption);
+	// SetWindowText(g_hWndMain, szCaption);
 }
diff --git a/source/terrax/terrax.h b/source/terrax/terrax.h
index f334b9129a266c34266b1ac2e9c7f3835ccd06fa..7d9877817d1627f1ef3ebd2f76c88be708226547 100644
--- a/source/terrax/terrax.h
+++ b/source/terrax/terrax.h
@@ -26,6 +26,9 @@
 #define AB_BUTTON_HEIGHT        40
 #define OBJECT_TREE_HEIGHT      300
 
+
+#define WM_SETTITLEASYNC (WM_USER + 1)
+
 #include "Grid.h"
 
 enum X_VIEWPORT_LAYOUT
diff --git a/source/wavplugin/AudioCodecWave.cpp b/source/wavplugin/AudioCodecWave.cpp
index 4bc4229df7fba3e339603b4bc1eacf076107208c..3f4330601577e19fc66dd791319127c25d2d6f98 100644
--- a/source/wavplugin/AudioCodecWave.cpp
+++ b/source/wavplugin/AudioCodecWave.cpp
@@ -3,16 +3,17 @@
 
 //##########################################################################
 
-CAudioCodecWave::CAudioCodecWave()
+CAudioCodecWave::CAudioCodecWave(IFileSystem *pFileSystem)
 {
+	m_pFileSystem = pFileSystem;
 	m_aExts.push_back("wav");
 }
 
 bool XMETHODCALLTYPE CAudioCodecWave::open(const char *szFile, const char *szArg, IXAudioCodecTarget **ppTarget, bool forSave)
 {
-	FILE *pFile = fopen(szFile, (forSave ? "wb" : "rb"));
+	IFile *pFile = m_pFileSystem->openFile(szFile, (forSave ? FILE_MODE_WRITE : FILE_MODE_READ));
 
-	if (!pFile || !ppTarget)
+	if (!pFile || !ppTarget && (forSave && (!szArg && strcasecmp(szArg, getFormat()) != 0)))
 		return false;
 
 	AudioRawDesc oDesc;
@@ -20,10 +21,10 @@ bool XMETHODCALLTYPE CAudioCodecWave::open(const char *szFile, const char *szArg
 
 	if(!forSave)
 	{
-		uint32_t uCurrPos = ftell(pFile);
-		fseek(pFile, 0, SEEK_SET);
-		fread(&oHeader, 1, sizeof(CWaveHeader), pFile);
-		fseek(pFile, 0, uCurrPos);
+		size_t uCurrPos = pFile->getPos();
+		pFile->setPos(0);
+		pFile->readBin(&oHeader, sizeof(CWaveHeader));
+		pFile->setPos(uCurrPos);
 
 		bool can =
 				memcmp(oHeader.aRiff, "RIFF", 4) == 0 &&
@@ -33,7 +34,7 @@ bool XMETHODCALLTYPE CAudioCodecWave::open(const char *szFile, const char *szArg
 
 		if(!can)
 		{
-			fclose(pFile);
+			mem_release(pFile);
 			return false;
 		}
 
@@ -87,12 +88,12 @@ UINT XMETHODCALLTYPE CAudioCodecWave::getExtCount() const
 
 CAudioCodecTargetWave::~CAudioCodecTargetWave()
 {
-	fclose(m_pFile);
+	mem_release(m_pFile);
 }
 
 //**************************************************************************
 
-void CAudioCodecTargetWave::init(FILE *pFile, CWaveHeader *pHeader, AudioRawDesc *pDesc, bool forSave)
+void CAudioCodecTargetWave::init(IFile *pFile, CWaveHeader *pHeader, AudioRawDesc *pDesc, bool forSave)
 {
 	m_pFile = pFile;
 
@@ -122,7 +123,7 @@ int64_t XMETHODCALLTYPE CAudioCodecTargetWave::getPos() const
 	if(!m_pFile || m_forSave)
 		return 0;
 
-	return ftell(m_pFile) - sizeof(CWaveHeader);
+	return m_pFile->getPos() - sizeof(CWaveHeader);
 }
 
 //**************************************************************************
@@ -132,7 +133,7 @@ void XMETHODCALLTYPE CAudioCodecTargetWave::setPos(int64_t iPos)
 	if(!m_pFile || m_forSave)
 		return;
 
-	fseek(m_pFile, sizeof(CWaveHeader) + iPos, SEEK_SET);
+	m_pFile->setPos(sizeof(CWaveHeader) + iPos);
 }
 
 //**************************************************************************
@@ -144,7 +145,7 @@ size_t XMETHODCALLTYPE CAudioCodecTargetWave::decode(int64_t iPos, uint64_t uLen
 
 	setPos(iPos);
 
-	size_t sizeRead = fread(*ppData, 1, uLen, m_pFile);
+	size_t sizeRead = m_pFile->readBin(*ppData, uLen);
 
 	return sizeRead;
 }
@@ -156,7 +157,7 @@ bool XMETHODCALLTYPE CAudioCodecTargetWave::encode(IXBuffer *pBufferPCM, AudioRa
 	if (!pBufferPCM || !pOutDesc)
 		return false;
 
-	fseek(m_pFile, 0, SEEK_SET);
+	m_pFile->setPos(0);
 
 	CWaveHeader oOutHeader;
 	oOutHeader.iSampleRate = pOutDesc->uSampleRate;
@@ -173,8 +174,8 @@ bool XMETHODCALLTYPE CAudioCodecTargetWave::encode(IXBuffer *pBufferPCM, AudioRa
 	oOutHeader.i16FormatCode = (pOutDesc->fmtSample > AUDIO_SAMPLE_FMT_SINT32 ? WAVE_FORMAT_PCM_FLOAT : WAVE_FORMAT_PCM_INT);
 	oOutHeader.uFormatChunkSize = 16;
 
-	fwrite(&oOutHeader, sizeof(oOutHeader), 1, m_pFile);
-	fwrite(pBufferPCM->get(), 1, pBufferPCM->size(), m_pFile);
+	m_pFile->writeBin(&oOutHeader, sizeof(oOutHeader));
+	m_pFile->writeBin(pBufferPCM->get(), pBufferPCM->size());
 
 	return true;
 }
diff --git a/source/wavplugin/AudioCodecWave.h b/source/wavplugin/AudioCodecWave.h
index 8dbc13d68bf743b110dd11dc0514cead3bd2fd82..b608972ed059dff44c8b350bcca48584ab30075b 100644
--- a/source/wavplugin/AudioCodecWave.h
+++ b/source/wavplugin/AudioCodecWave.h
@@ -9,6 +9,8 @@ See the license in LICENSE
 
 #include <xcommon/IXAudioCodec.h>
 #include <common/string.h>
+#include <xcommon/IFileSystem.h>
+#include <core/IFile.h>
 
 //##########################################################################
 
@@ -40,7 +42,9 @@ struct CWaveHeader
 class CAudioCodecWave: public IXUnknownImplementation<IXAudioCodec>
 {
 public:
-	CAudioCodecWave();
+	CAudioCodecWave(IFileSystem *pFileSystem);
+
+	XIMPLEMENT_VERSION(IXAUDIOCODEC_VERSION);
 
 	virtual const char* XMETHODCALLTYPE getFormat() const override;
 	virtual const char* XMETHODCALLTYPE getExt(UINT uIndex=0) const override;
@@ -50,6 +54,7 @@ public:
 
 protected:
 	Array<String> m_aExts;
+	IFileSystem *m_pFileSystem = NULL;
 };
 
 //##########################################################################
@@ -68,9 +73,9 @@ protected:
 
 	friend CAudioCodecWave;
 
-	void init(FILE *pFile, CWaveHeader *pHeader, AudioRawDesc *pDesc, bool forSave);
+	void init(IFile *pFile, CWaveHeader *pHeader, AudioRawDesc *pDesc, bool forSave);
 
-	FILE *m_pFile = NULL;
+	IFile *m_pFile = NULL;
 	CWaveHeader m_oHeader;
 	AudioRawDesc m_oDesc;
 	bool m_forSave = false;
diff --git a/source/wavplugin/plugin_main.cpp b/source/wavplugin/plugin_main.cpp
index aa4a37729f84118137101dc2b8ba72f703eaa5fe..67f4c9a1b1749607d9dfc58694668f11eb3fab15 100644
--- a/source/wavplugin/plugin_main.cpp
+++ b/source/wavplugin/plugin_main.cpp
@@ -14,6 +14,7 @@ class CAudioCodecWav: public IXUnknownImplementation<IXPlugin>
 public:
 	void XMETHODCALLTYPE startup(IXCore *pCore) override
 	{
+		m_pCore = pCore;
 	}
 
 	void XMETHODCALLTYPE shutdown() override
@@ -41,10 +42,13 @@ public:
 	{
 		if (guid == IXAUDIOCODEC_GUID)
 		{
-			return(new CAudioCodecWave());
+			return(new CAudioCodecWave(m_pCore->getFileSystem()));
 		}
 		return(NULL);
 	}
+
+protected:
+	IXCore *m_pCore = NULL;
 };
 
 DECLARE_XPLUGIN(CAudioCodecWav);
diff --git a/source/xEngine/Engine.cpp b/source/xEngine/Engine.cpp
index a562c741f329795b40ab4be4aad3cf14c7f70071..2984a6709e3ea16b62c748c13f7668dc106aae79 100644
--- a/source/xEngine/Engine.cpp
+++ b/source/xEngine/Engine.cpp
@@ -6,6 +6,8 @@
 
 #include "SkyXEngine.h"
 
+#include <xcommon/IXSoundSystem.h>
+
 #ifdef _DEBUG
 #	pragma comment(lib, "sxcore_d.lib")
 #else
@@ -121,6 +123,7 @@ CEngine::CEngine(int argc, char **argv, const char *szName)
 	INIT_OUTPUT_STREAM(m_pCore);
 	LibReport(REPORT_MSG_LEVEL_NOTICE, "LIB core initialized\n");
 
+	m_pObserverChangedEventChannel = m_pCore->getEventChannel<XEventObserverChanged>(EVENT_OBSERVER_CHANGED_GUID);
 
 	Core_0RegisterCVarString("engine_version", SKYXENGINE_VERSION, "Текущая версия движка", FCVAR_READONLY);
 
@@ -159,6 +162,49 @@ bool XMETHODCALLTYPE CEngine::initGraphics(XWINDOW_OS_HANDLE hWindow, IXEngineCa
 	SSInput_0Create("sxinput", (HWND)hWindow, false);
 	LibReport(REPORT_MSG_LEVEL_NOTICE, "LIB input initialized\n");
 
+
+
+	// init sound
+	AudioRawDesc oAudioDesc;
+	oAudioDesc.u8Channels = 2;
+	oAudioDesc.fmtSample = AUDIO_SAMPLE_FMT_SINT16;
+	oAudioDesc.uSampleRate = 44100;
+	oAudioDesc.calc();
+
+	IXSoundSystem *pSound = (IXSoundSystem*)(m_pCore->getPluginManager()->getInterface(IXSOUNDSYSTEM_GUID));
+	IXSoundLayer *pMasterLayer = pSound->createMasterLayer(&oAudioDesc, "master");
+	pMasterLayer->play(true);
+	/*IXSoundPlayer *pPlayer = pMasterLayer->newSoundPlayer("sounds/guitar_10.ogg", SOUND_DTYPE_3D);
+	pPlayer->setWorldPos(float3(-11.084, 0.435, -18.707));
+	pPlayer->setLoop(SOUND_LOOP_SIMPLE);
+	pPlayer->play();*/
+	/*IXSoundEmitter *pEmitter = pMasterLayer->newSoundEmitter("sounds/ak74_shoot.ogg", SOUND_DTYPE_2D);
+	//pEmitter->play();
+
+	IXSoundEmitter *pEmitter2 = pMasterLayer->newSoundEmitter("sounds/ak74_shoot.ogg", SOUND_DTYPE_2D);
+	//pEmitter2->play();
+
+	while (1)
+	{
+		if (GetAsyncKeyState('I'))
+		{
+			pEmitter2->play();
+			Sleep(100);
+		}
+
+		if (GetAsyncKeyState('Q'))
+			pMasterLayer->play(false);
+		
+		if (GetAsyncKeyState('W'))
+			pMasterLayer->play(true);
+
+		float3 v;
+		pSound->update(v,v,v);
+	}*/
+	LibReport(REPORT_MSG_LEVEL_NOTICE, "LIB sound initialized\n");
+
+
+
 	// init graphics
 	Core_0RegisterCVarInt("r_win_width", 800, "Размер окна по горизонтали (в пикселях)", FCVAR_NOTIFY_OLD);
 	Core_0RegisterCVarInt("r_win_height", 600, "Размер окна по вертикали (в пикселях)", FCVAR_NOTIFY_OLD);
@@ -198,6 +244,10 @@ bool XMETHODCALLTYPE CEngine::initGraphics(XWINDOW_OS_HANDLE hWindow, IXEngineCa
 	LibReport(REPORT_MSG_LEVEL_NOTICE, "LIB render initialized\n");
 
 
+	
+
+
+
 	// init game
 	SGame_0Create((HWND)hWindow, true);
 	LibReport(REPORT_MSG_LEVEL_NOTICE, "LIB game initialized\n");
@@ -347,9 +397,14 @@ bool CEngine::runFrame()
 
 		if(pRenderContext)
 		{
-			SRender_SetCamera(m_pCallback->getCameraForFrame());
+			ICamera *pCamera = m_pCallback->getCameraForFrame();
+			SRender_SetCamera(pCamera);
 			SRender_UpdateView();
 
+			XEventObserverChanged ev;
+			ev.pCamera = pCamera;
+			m_pObserverChangedEventChannel->broadcastEvent(&ev);
+
 			IXRenderPipeline *pRenderPipeline;
 			m_pCore->getRenderPipeline(&pRenderPipeline);
 
diff --git a/source/xEngine/Engine.h b/source/xEngine/Engine.h
index 1333bed8601f2f4aa846bdbd500203d156a1ef9f..e865577703204300b148985c086e9344be4818fc 100644
--- a/source/xEngine/Engine.h
+++ b/source/xEngine/Engine.h
@@ -55,6 +55,8 @@ protected:
 
 	IXUI *m_pXUI = NULL;
 
+	IEventChannel<XEventObserverChanged> *m_pObserverChangedEventChannel = NULL;
+
 #ifdef USE_BREAKPAD
 	google_breakpad::ExceptionHandler *m_pBreakpadHandler = NULL;
 #endif
diff --git a/source/xSound/AudioConverter.h b/source/xSound/AudioConverter.h
new file mode 100644
index 0000000000000000000000000000000000000000..1284fb95bc4563cc1452fa2829742fc1c4a32a6f
--- /dev/null
+++ b/source/xSound/AudioConverter.h
@@ -0,0 +1,165 @@
+/*****************************************************
+Copyright © DogmaNet Team, 2020
+Site: dogmanet.ru
+See the license in LICENSE
+*****************************************************/
+
+#ifndef __AUDIOCONVERTER_H
+#define __AUDIOCONVERTER_H
+
+#include "SoundTypes.h"
+
+#include <mital_fn.h>
+
+//##########################################################################
+
+inline bool AudioResampling(void *pIn, AudioRawDesc *pInDesc, IXBuffer *pOut, AudioRawDesc *pToDesc)
+{
+	if (pToDesc->uSampleRate == pInDesc->uSampleRate)
+		return false;
+
+	/*pOut->alloc(pInDesc->uSize);
+	memcpy(pOut->get(), pIn, pInDesc->uSize);
+	return true;*/
+
+
+	BYTE *pSrcData = 0;
+
+	if (pOut->size() > 0)
+		pSrcData = pOut->get();
+	else
+		pSrcData = (BYTE*)pIn;
+
+	int iCountElem = pInDesc->uSize / AudioGetFormatBytes(pInDesc->fmtSample);
+	double fCoef = double(pToDesc->uSampleRate) / double(pInDesc->uSampleRate);
+	int iNewCountElem = (int)ceil(double(iCountElem) * fCoef);
+
+	uint32_t uSize = AudioGetFormatBytes(pInDesc->fmtSample) * iNewCountElem;
+	BYTE *pDestData = new BYTE[uSize];
+
+	//считаем коэффициент добавления на каждом семпле
+	double fAdd = double(iCountElem) / double(iNewCountElem);
+
+	//проход по каналам
+	for (auto iChannels = 0u; iChannels < pInDesc->u8Channels; ++iChannels)
+	{
+		int iCurrNewpos = 0;
+		int iLast = 0;
+		uint32_t iKey;
+
+		//проход по количеству семплов в каждом канале
+		for (auto i = 0, il = iNewCountElem / pInDesc->u8Channels; i < il; ++i)
+		{
+			//текущая позиция до которой надо дойти в исходном массиве
+			int iCurr = (int)ceil(fAdd*((i + 1) * pInDesc->u8Channels));
+
+			//сколько элементов из исходного массива надо смешать
+			int iCount = (int)max(iCurr - iLast, (int)max(fAdd, 1.0));
+
+			double fCountMixed = 0;
+
+			//берем данные из исходного массива и смешиваем
+			for (auto k = 0; k < iCount; ++k)
+			{
+				iKey = iChannels + ((iLast + k) / pInDesc->u8Channels) * pInDesc->u8Channels;
+				iKey = clamp<int>(iKey, 0, iCountElem - 1);
+
+				double fOrigin = RawDataRead(pSrcData, iKey, pInDesc->fmtSample);
+				fCountMixed += fOrigin;
+			}
+
+			//записываем микс в целевой массив
+			iCurrNewpos = iChannels + i * pInDesc->u8Channels;
+			RawDataWrite(pDestData, iCurrNewpos, pInDesc->fmtSample, (fCountMixed / double(iCount)));
+
+			//запоминаем до куда дошли в этой итреации
+			iLast = iCurr;
+		}
+
+		int iSub = iCountElem - iLast;
+		int iSub3 = (int)(iNewCountElem * fAdd);
+		int qwerty = 0;
+	}
+
+	int qwerty = 0;
+
+	if (pOut->size() > 0)
+		pOut->free();
+
+	pOut->alloc(uSize);
+	memcpy(pOut->get(), pDestData, uSize);
+
+	mem_delete_a(pDestData);
+
+	return true;
+}
+
+//**************************************************************************
+
+inline bool AudioRechannels(void *pIn, AudioRawDesc *pInDesc, IXBuffer *pOut, AudioRawDesc *pToDesc)
+{
+	return false;
+	/*BYTE *pSrcData = 0;
+
+	if (pOut->size() > 0)
+	pSrcData = pOut->get();
+	else
+	pSrcData = (BYTE*)pIn;
+
+	uint32_t uSize = 0;
+
+	if (pInDesc->u8Channels )*/
+}
+
+//**************************************************************************
+
+inline bool AudioReformat(void *pIn, AudioRawDesc *pInDesc, IXBuffer *pOut, AudioRawDesc *pToDesc)
+{
+	if (pInDesc->fmtSample == pToDesc->fmtSample)
+		return false;
+
+	BYTE *pSrcData = 0;
+
+	if (pOut->size() > 0)
+		pSrcData = pOut->get();
+	else
+		pSrcData = (BYTE*)pIn;
+
+	uint32_t uCountElem = (pInDesc->uSize / AudioGetFormatBytes(pInDesc->fmtSample));
+	uint32_t uSize = AudioGetFormatBytes(pToDesc->fmtSample) * uCountElem;
+	BYTE *pDestData = new BYTE[uSize];
+
+	for (auto i = 0u; i < uCountElem; ++i)
+	{
+		double fSample = RawDataRead(pSrcData, i, pInDesc->fmtSample);
+		RawDataWrite(pDestData, i, pToDesc->fmtSample, fSample);
+	}
+
+	if (pOut->size() > 0)
+		pOut->free();
+
+	pOut->alloc(uSize);
+	memcpy(pOut->get(), pDestData, uSize);
+
+	mem_delete_a(pDestData);
+
+	return true;
+}
+
+//**************************************************************************
+
+inline bool AudioConverter(void *pIn, AudioRawDesc *pInDesc, IXBuffer *pOut, AudioRawDesc *pToDesc)
+{
+	if (pInDesc->uSampleRate != pToDesc->uSampleRate)
+		AudioResampling(pIn, pInDesc, pOut, pToDesc);
+
+	if (pInDesc->u8Channels != pToDesc->u8Channels && pToDesc->u8Channels <= 2 && pToDesc->u8Channels >= 1)
+		AudioRechannels(pIn, pInDesc, pOut, pToDesc);
+
+	if (pInDesc->fmtSample != pToDesc->fmtSample)
+		AudioReformat(pIn, pInDesc, pOut, pToDesc);
+
+	return true;
+}
+
+#endif
\ No newline at end of file
diff --git a/source/xSound/SoundBase.cpp b/source/xSound/SoundBase.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8b28f7f1664347d22e4ad17e3a6e64b760c913f6
--- /dev/null
+++ b/source/xSound/SoundBase.cpp
@@ -0,0 +1,49 @@
+
+#include "SoundBase.h"
+
+//##########################################################################
+
+SOUND_DTYPE XMETHODCALLTYPE CSoundBase::getType()
+{
+	return m_dtype;
+}
+
+void XMETHODCALLTYPE CSoundBase::setVolume(float fVolume)
+{
+	m_fVolume = fVolume;
+}
+
+float XMETHODCALLTYPE CSoundBase::getVolume() const
+{
+	return m_fVolume;
+}
+
+void XMETHODCALLTYPE CSoundBase::setPan(float fPan)
+{
+	m_fPan = fPan;
+}
+
+float XMETHODCALLTYPE CSoundBase::getPan() const
+{
+	return m_fPan;
+}
+
+const float3& XMETHODCALLTYPE CSoundBase::getWorldPos() const
+{
+	return m_vWorldPos;
+}
+
+void XMETHODCALLTYPE CSoundBase::setWorldPos(const float3 &vPos)
+{
+	m_vWorldPos = vPos;
+}
+
+float XMETHODCALLTYPE CSoundBase::getDistance() const
+{
+	return m_fDist;
+}
+
+void XMETHODCALLTYPE CSoundBase::setDistance(float fDist)
+{
+	m_fDist = fDist;
+}
diff --git a/source/xSound/SoundBase.h b/source/xSound/SoundBase.h
new file mode 100644
index 0000000000000000000000000000000000000000..b6de20455067cc5a644c4d349da116808d2e05ca
--- /dev/null
+++ b/source/xSound/SoundBase.h
@@ -0,0 +1,77 @@
+/*****************************************************
+Copyright © DogmaNet Team, 2020
+Site: dogmanet.ru
+See the license in LICENSE
+*****************************************************/
+
+#ifndef __SOUNDBASE_H
+#define __SOUNDBASE_H
+
+#include <common/types.h>
+#include <common/math.h>
+#include <common/string.h>
+#include <xcommon/IXSoundSystem.h>
+#include <mital.h>
+
+#include "SoundTypes.h"
+
+//##########################################################################
+
+class CSoundBase: public IXUnknownVirtualImplementation<IXSoundBase>
+{
+public:
+
+	SX_ALIGNED_OP_MEM
+
+	virtual SOUND_DTYPE XMETHODCALLTYPE getType() final;
+
+	virtual void XMETHODCALLTYPE setVolume(float fVolume) final;
+	virtual float XMETHODCALLTYPE getVolume() const final;
+
+	virtual void XMETHODCALLTYPE setPan(float fPan) final;
+	virtual float XMETHODCALLTYPE getPan() const final;
+
+	virtual const float3& XMETHODCALLTYPE getWorldPos() const final;
+	virtual void XMETHODCALLTYPE setWorldPos(const float3 &vPos) final;
+
+	virtual float XMETHODCALLTYPE getDistance() const final;
+	virtual void XMETHODCALLTYPE setDistance(float fDist) final;
+
+protected:
+
+	friend CSoundLayer;
+
+	void update();
+
+	bool create(SOUND_DTYPE type, const char *szName, CSoundLayer *pLayer, CSoundSystem *pSoundSystem);
+
+	//************************************************************************
+
+	float m_fVolume = 1.f;
+	float m_fPan = 0.f;
+
+	//! аудио буфер
+	//IAudioBuffer *m_pAB = NULL;
+
+	//! дистанция слышимости
+	float m_fDist = 10.f;
+
+	//! мировая позиция звука
+	float3 m_vWorldPos;
+
+	//! тип звука
+	SOUND_DTYPE m_dtype = SOUND_DTYPE_2D;
+
+	//! состояние проигрывания
+	SOUND_STATE m_state = SOUND_STATE_STOP;
+
+	//! строковый идентификатор звука
+	String m_sName = "";
+
+	//! слой владелец
+	CSoundLayer *m_pLayer = NULL;
+
+	//CSoundSystem *m_pSoundSystem = NULL;
+};
+
+#endif
diff --git a/source/xSound/SoundEmitter.cpp b/source/xSound/SoundEmitter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1536107900c2500a040da7656b8a81894faee83d
--- /dev/null
+++ b/source/xSound/SoundEmitter.cpp
@@ -0,0 +1,133 @@
+
+#include "SoundEmitter.h"
+
+#include "SoundLoader.h"
+#include "SoundLayer.h"
+
+//##########################################################################
+
+CSoundEmitter::~CSoundEmitter()
+{
+	m_pLayer->delSndEmitter(this);
+
+}
+
+//**************************************************************************
+
+CSoundEmitter* CSoundEmitter::newInstance()
+{
+	CSoundEmitter *pEmitter = new CSoundEmitter();
+
+	pEmitter->m_aInstances[0].pAB = m_aInstances[0].pAB->newInstance();
+	pEmitter->m_dtype = this->m_dtype;
+	pEmitter->m_state = SOUND_STATE_STOP;
+	pEmitter->m_sName = this->m_sName;
+	pEmitter->m_pLayer = this->m_pLayer;
+	pEmitter->m_fDist = this->m_fDist;
+	pEmitter->m_vWorldPos = this->m_vWorldPos;
+	return pEmitter;
+}
+
+//**************************************************************************
+
+void XMETHODCALLTYPE CSoundEmitter::play()
+{
+	//если родительский слой не проигрывается, тогда не запускаем проигрывание
+	if (!m_pLayer->isPlaying())
+		return;
+
+	float3 vPos, vLook, vUp;
+	m_pLayer->getObserverParam(&vPos, &vLook, &vUp);
+
+	IAudioBuffer *pAB = NULL;
+
+	//проход по массиву инстансов звука, если есть первый попавшийся не проигрываемые тогда его проигрываем
+	for (int i = 0, il = m_aInstances.size(); i<il; ++i)
+	{
+		if (!(m_aInstances[i].pAB->isPlaying()))
+		{
+			pAB = m_aInstances[i].pAB;
+			continue;
+		}
+	}
+
+	if (!pAB)
+	{
+		//если пришли сюда, значит нет свободных инстансов, создаем новый и проигрыаем
+		IAudioBuffer *pInst = m_aInstances[0].pAB->newInstance();
+		pAB = pInst;
+		m_aInstances.push_back(pInst);
+	}
+
+	Com3D(pAB, m_fDist, m_vWorldPos, vPos, vLook, vUp);
+	pAB->play(true);
+}
+
+//**************************************************************************
+
+void CSoundEmitter::resume()
+{
+	//если инстансы проигрывались тогда включаем проигрывание
+	for (int i = 0, il = m_aInstances.size(); i < il; ++i)
+	{
+		if(m_aInstances[i].isPlaying)
+			m_aInstances[i].pAB->play(true);
+	}
+}
+
+void CSoundEmitter::pause()
+{
+	//записываем состояния инстансов и останавливаем
+	for (int i = 0, il = m_aInstances.size(); i < il; ++i)
+	{
+		m_aInstances[i].isPlaying = m_aInstances[i].pAB->isPlaying();
+		m_aInstances[i].pAB->play(false);
+	}
+}
+
+//**************************************************************************
+
+bool CSoundEmitter::create(CSoundLayer *pLayer, IXAudioCodecTarget *pCodecTarget, SOUND_DTYPE dtype)
+{
+	if (!pCodecTarget || !pLayer)
+		return false;
+
+	m_dtype = dtype;
+	AudioRawDesc oDesc;
+	pCodecTarget->getDesc(&oDesc);
+	m_pLayer = pLayer;
+
+	IAudioBuffer *pAB = pLayer->createAudioBuffer(AB_TYPE_SECOND, &oDesc);
+	BYTE *pData = new BYTE[oDesc.uSize];
+	pCodecTarget->decode(0, oDesc.uSize, (void**)&pData);
+
+	BYTE *pData2;
+	pAB->lock(AB_LOCK_WRITE, (void**)&pData2);
+	memcpy(pData2, pData, oDesc.uSize);
+	pAB->unlock();
+
+	mem_delete_a(pData);
+	mem_release(pCodecTarget);
+
+	pAB->setLoop(AB_LOOP_NONE);
+
+	m_aInstances.push_back(Instance(pAB));
+
+	return true;
+}
+
+//##########################################################################
+
+void CSoundEmitter::update(const float3 &vListenerPos, const float3 &vListenerDir, const float3 &vListenerUp)
+{
+	if (m_dtype == SOUND_DTYPE_2D)
+		return;
+
+	for (int i = 0, il = m_aInstances.size(); i < il; ++i)
+	{
+		if (m_aInstances[i].pAB->isPlaying())
+		{
+			Com3D(m_aInstances[i].pAB, m_fDist, m_vWorldPos, vListenerPos, vListenerDir, vListenerUp);
+		}
+	}
+}
\ No newline at end of file
diff --git a/source/xSound/SoundEmitter.h b/source/xSound/SoundEmitter.h
new file mode 100644
index 0000000000000000000000000000000000000000..318fe788508b13b01c80c87f6692a9f113c285e8
--- /dev/null
+++ b/source/xSound/SoundEmitter.h
@@ -0,0 +1,55 @@
+/*****************************************************
+Copyright © DogmaNet Team, 2020
+Site: dogmanet.ru
+See the license in LICENSE
+*****************************************************/
+
+#ifndef __SOUNDEMITTER_H
+#define __SOUNDEMITTER_H
+
+#include <xcommon/IXSoundSystem.h>
+#include "SoundBase.h"
+#include <mital.h>
+
+#include "SoundTypes.h"
+#include "SoundSystem.h"
+
+//##########################################################################
+
+class CSoundEmitter : public CSoundBase, public virtual IXSoundEmitter
+{
+public:
+	~CSoundEmitter();
+
+	//! создание нового инстанса CSoundEmitter
+	CSoundEmitter* newInstance();
+
+	virtual void XMETHODCALLTYPE play() override;
+
+	//! продолжить проигрывание инстансов, если они проигрывались
+	void resume();
+
+	//! остановка проигрывания
+	void pause();
+
+	void update(const float3 &vListenerPos, const float3 &vListenerDir, const float3 &vListenerUp);
+
+protected:
+
+	friend CSoundLayer;
+
+	bool create(CSoundLayer *pLayer, IXAudioCodecTarget *pCodecTarget, SOUND_DTYPE dtype);
+
+	struct Instance
+	{
+		Instance() = default;
+		Instance(IAudioBuffer *pBuffer) { pAB = pBuffer; }
+		~Instance() { mem_release(pAB); }
+		IAudioBuffer *pAB = NULL;
+		bool isPlaying = false;
+	};
+
+	Array<Instance> m_aInstances;
+};
+
+#endif
diff --git a/source/xSound/SoundLayer.cpp b/source/xSound/SoundLayer.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..88ef9d7594ccbcbd6537ffdc423c026a6cd1b164
--- /dev/null
+++ b/source/xSound/SoundLayer.cpp
@@ -0,0 +1,320 @@
+
+#include "SoundLayer.h"
+
+#include "SoundEmitter.h"
+#include "SoundPlayer.h"
+#include "SoundSystem.h"
+
+//##########################################################################
+
+CSoundLayer::~CSoundLayer()
+{
+	if (m_pParent)
+		m_pParent->delLayer(this);
+
+	for (maplayer::Iterator i = m_mapLayers.begin(); i; i++)
+	{
+		mem_release(m_mapLayers[i.first]);
+		m_mapLayers.erase(i.first);
+	}
+
+	for (mapsoundplayer::Iterator i = m_mapSndPlayers.begin(); i; i++)
+	{
+		mem_release(m_mapSndPlayers[i.first]);
+		m_mapSndPlayers.erase(i.first);
+	}
+
+	int iCount0 = m_mapSndEmitters.Size();
+	for (mapsoundemitter::Iterator i = m_mapSndEmitters.begin(); i; i++)
+	{
+		mem_release(m_mapSndEmitters[i.first]);
+		m_mapSndEmitters.erase(i.first);
+	}
+
+	mem_release_del(m_pPrimaryBuffer);
+}
+
+//**************************************************************************
+
+bool CSoundLayer::init(CSoundSystem *pSoundSystem, CSoundLayer *pParent, const AudioRawDesc *pDesc, const char *szName)
+{
+	if (!pDesc || !pSoundSystem)
+		return false;
+
+	if (m_mapLayers.KeyExists(szName))
+	{
+		return false;
+	}
+
+	AudioRawDesc oDesc = *pDesc;
+	oDesc.uSize = 0;
+
+	if (pParent == NULL)
+		m_pPrimaryBuffer = pSoundSystem->createMasterBuffer(&oDesc);
+	else
+		m_pPrimaryBuffer = dynamic_cast<IAudioBufferEx*>(createAudioBuffer(AB_TYPE_PRIMARY, &oDesc));
+
+	m_sName = szName;
+	m_pParent = pParent;
+	m_pSoundSystem = pSoundSystem;
+
+	return true;
+}
+
+//**************************************************************************
+
+void CSoundLayer::addLayer(CSoundLayer *pLayer, const char *szName)
+{
+	m_mapLayers[szName] = pLayer;
+}
+
+void CSoundLayer::delLayer(const CSoundLayer *pLayer)
+{
+	for (maplayer::Iterator i = m_mapLayers.begin(); i; i++)
+	{
+		if (m_mapLayers[i.first] == pLayer)
+		{
+			m_mapLayers.erase(i.first);
+			break;
+		}
+	}
+}
+
+//**************************************************************************
+
+void CSoundLayer::addSndPlayer(CSoundPlayer *pSndPlayer, const char *szName)
+{
+	m_mapSndPlayers[szName] = pSndPlayer;
+}
+
+void CSoundLayer::delSndPlayer(const CSoundPlayer *pSndPlayer)
+{
+	for (mapsoundplayer::Iterator i = m_mapSndPlayers.begin(); i; i++)
+	{
+		if (m_mapSndPlayers[i.first] == pSndPlayer)
+		{
+			m_mapSndPlayers[i.first] = NULL;
+			m_mapSndPlayers.erase(i.first);
+			break;
+		}
+	}
+}
+
+//**************************************************************************
+
+void CSoundLayer::addSndEmitter(CSoundEmitter *pSndEmitter, const char *szName)
+{
+	m_mapSndEmitters[szName] = pSndEmitter;
+}
+
+void CSoundLayer::delSndEmitter(const CSoundEmitter *pSndEmitter)
+{
+	int iCount0 = m_mapSndEmitters.Size();
+	for (mapsoundemitter::Iterator i = m_mapSndEmitters.begin(); i; i++)
+	{
+		if (m_mapSndEmitters[i.first] == pSndEmitter)
+		{
+			m_mapSndEmitters[i.first] = NULL;
+			m_mapSndEmitters.erase(i.first);
+			break;
+		}
+	}
+	int iCount1 = m_mapSndEmitters.Size();
+	int qwerty = 0;
+}
+
+//**************************************************************************
+
+void XMETHODCALLTYPE CSoundLayer::getDesc(AudioRawDesc *pDesc) const
+{
+	if (!m_pPrimaryBuffer)
+		return;
+
+	m_pPrimaryBuffer->getDesc(pDesc);
+}
+
+//**************************************************************************
+
+const char* XMETHODCALLTYPE CSoundLayer::getName() const
+{
+	return m_sName.c_str();
+}
+
+//**************************************************************************
+
+IXSoundLayer* XMETHODCALLTYPE CSoundLayer::findLayer(const char *szName)
+{
+	if (!szName)
+		return NULL;
+
+	if (strcasecmp(this->getName(), szName) == 0)
+		return this;
+
+	IXSoundLayer *pFound = NULL;
+
+	for (maplayer::Iterator i = m_mapLayers.begin(); i; i++)
+	{
+		if ((pFound = m_mapLayers[i.first]->findLayer(szName)))
+			break;
+	}
+
+	return pFound;
+}
+
+//**************************************************************************
+
+uint32_t CSoundLayer::getStreamChunkSize(AudioRawDesc *pDesc) const
+{
+	return m_pPrimaryBuffer->getStreamChunkSize(pDesc);
+}
+
+IAudioBuffer* CSoundLayer::createAudioBuffer(AB_TYPE type, const AudioRawDesc *pDesc)
+{
+	return m_pPrimaryBuffer->createAudioBuffer(type, pDesc);
+}
+
+//**************************************************************************
+
+IXSoundLayer* XMETHODCALLTYPE CSoundLayer::newSoundLayer(const AudioRawDesc *pDesc, const char *szName)
+{
+	if (!pDesc)
+		return NULL;
+
+	if (!matchPrimaryLayer(pDesc))
+		return NULL;
+
+	CSoundLayer *pLayer = new CSoundLayer();
+	pLayer->init(m_pSoundSystem, this, pDesc, szName);
+
+	addLayer(pLayer, szName);
+
+	return pLayer;
+}
+
+IXSoundEmitter* XMETHODCALLTYPE CSoundLayer::newSoundEmitter(const char *szName, SOUND_DTYPE dtype)
+{
+	if (!szName)
+		return NULL;
+
+	CSoundEmitter *pEmitter = NULL;
+
+	if (m_mapSndEmitters.KeyExists(szName))
+	{
+		CSoundEmitter *pEmitterOrigin = m_mapSndEmitters[szName];
+		pEmitter = pEmitterOrigin->newInstance();
+	}
+	else
+	{
+		IXAudioCodecTarget *pCodecTarget = m_pSoundSystem->getCodecTarget(szName);
+		if (!pCodecTarget)
+			return NULL;
+
+		pEmitter = new CSoundEmitter();
+		pEmitter->create(this, pCodecTarget, dtype);
+	}
+
+	addSndEmitter(pEmitter, szName);
+
+	return pEmitter;
+}
+
+IXSoundPlayer* XMETHODCALLTYPE CSoundLayer::newSoundPlayer(const char *szName, SOUND_DTYPE dtype)
+{
+	if (!szName)
+		return NULL;
+
+	CSoundPlayer *pPlayer = NULL;
+
+	if (m_mapSndPlayers.KeyExists(szName))
+	{
+		if (m_mapSndPlayers[szName])
+			pPlayer = m_mapSndPlayers[szName];
+		//return pPlayer->newInstance();
+	}
+	else
+	{
+		IXAudioCodecTarget *pCodecTarget = m_pSoundSystem->getCodecTarget(szName);
+		if (!pCodecTarget)
+			return NULL;
+
+		pPlayer = new CSoundPlayer();
+		pPlayer->create(this, pCodecTarget, dtype);
+	}
+
+	addSndPlayer(pPlayer, szName);
+
+	return pPlayer;
+}
+
+//##########################################################################
+
+void XMETHODCALLTYPE CSoundLayer::play(bool canPlay)
+{
+	if (m_isPlaying == canPlay || (m_pParent && !m_pParent->isPlaying() && canPlay))
+		return;
+
+	m_isPlaying = canPlay;
+
+	for (maplayer::Iterator i = m_mapLayers.begin(); i; i++)
+		m_mapLayers[i.first]->play(canPlay);
+
+	for (mapsoundplayer::Iterator i = m_mapSndPlayers.begin(); i; i++)
+	{
+		if (canPlay)
+			m_mapSndPlayers[i.first]->resume();
+		else
+			m_mapSndPlayers[i.first]->pause();
+	}
+
+	for (mapsoundemitter::Iterator i = m_mapSndEmitters.begin(); i; i++)
+	{
+		if (canPlay)
+			m_mapSndEmitters[i.first]->resume();
+		else
+			m_mapSndEmitters[i.first]->pause();
+	}
+
+	m_pPrimaryBuffer->play(canPlay);
+}
+
+bool XMETHODCALLTYPE CSoundLayer::isPlaying() const
+{
+	return m_isPlaying;
+}
+
+void CSoundLayer::update(const float3 &vListenerPos, const float3 &vListenerDir, const float3 &vListenerUp)
+{
+	for (maplayer::Iterator i = m_mapLayers.begin(); i; i++)
+	{
+		if (m_mapLayers[i.first])
+			m_mapLayers[i.first]->update(vListenerPos, vListenerDir, vListenerUp);
+	}
+
+	for (mapsoundplayer::Iterator i = m_mapSndPlayers.begin(); i; i++)
+	{
+		if (m_mapSndPlayers[i.first])
+			m_mapSndPlayers[i.first]->update(vListenerPos, vListenerDir, vListenerUp);
+	}
+
+	for (mapsoundemitter::Iterator i = m_mapSndEmitters.begin(); i; i++)
+	{
+		if (m_mapSndEmitters[i.first])
+			m_mapSndEmitters[i.first]->update(vListenerPos, vListenerDir, vListenerUp);
+	}
+}
+
+void CSoundLayer::getObserverParam(float3 *pPos, float3 *pLook, float3 *pUp)
+{
+	m_pSoundSystem->getObserverParam(pPos, pLook, pUp);
+}
+
+bool CSoundLayer::matchPrimaryLayer(const AudioRawDesc *pDesc)
+{
+	if (!pDesc || !m_pPrimaryBuffer)
+		return false;
+
+	AudioRawDesc oPrimaryDesc;
+	m_pPrimaryBuffer->getDesc(&oPrimaryDesc);
+
+	return (oPrimaryDesc.uSampleRate == pDesc->uSampleRate);
+}
diff --git a/source/xSound/SoundLayer.h b/source/xSound/SoundLayer.h
new file mode 100644
index 0000000000000000000000000000000000000000..06b901608f63450394188ee5cfb8fe29ea765f62
--- /dev/null
+++ b/source/xSound/SoundLayer.h
@@ -0,0 +1,92 @@
+/*****************************************************
+Copyright © DogmaNet Team, 2020
+Site: dogmanet.ru
+See the license in LICENSE
+*****************************************************/
+
+#ifndef __SOUNDLAYER_H
+#define __SOUNDLAYER_H
+
+#include <common/assotiativearray.h>
+#include <xcommon/IXSoundSystem.h>
+#include "SoundBase.h"
+#include <mital.h>
+
+#include "SoundTypes.h"
+
+//##########################################################################
+
+class CSoundLayer: public IXUnknownImplementation<IXSoundLayer>
+{
+public:
+
+	~CSoundLayer();
+
+	virtual void XMETHODCALLTYPE play(bool canPlay) override;
+	virtual bool XMETHODCALLTYPE isPlaying() const override;
+	virtual const char* XMETHODCALLTYPE getName() const override;
+
+	virtual IXSoundLayer* XMETHODCALLTYPE findLayer(const char *szName) override;
+
+	virtual IXSoundLayer* XMETHODCALLTYPE newSoundLayer(const AudioRawDesc *pDesc, const char *szName) override;
+	virtual IXSoundEmitter* XMETHODCALLTYPE newSoundEmitter(const char *szName, SOUND_DTYPE dtype) override;
+	virtual IXSoundPlayer* XMETHODCALLTYPE newSoundPlayer(const char *szName, SOUND_DTYPE dtype) override;
+
+	virtual void XMETHODCALLTYPE getDesc(AudioRawDesc *pDesc) const override;
+
+	uint32_t getStreamChunkSize(AudioRawDesc *pDesc) const;
+	IAudioBuffer* createAudioBuffer(AB_TYPE type, const AudioRawDesc *pDesc);
+
+	void update(const float3 &vListenerPos, const float3 &vListenerDir, const float3 &vListenerUp);
+
+	void getObserverParam(float3 *pPos, float3 *pLook, float3 *pUp);
+
+protected:
+
+	friend CSoundSystem;
+	friend CSoundPlayer;
+	friend CSoundEmitter;
+
+	bool init(CSoundSystem *pSoundSystem, CSoundLayer *pParent, const AudioRawDesc *pDesc, const char *szName);
+
+	//************************************************************************
+
+	void addLayer(CSoundLayer *pLayer, const char *szName);
+	void delLayer(const CSoundLayer *pLayer);
+
+	void addSndPlayer(CSoundPlayer *pSndPlayer, const char *szName);
+	void delSndPlayer(const CSoundPlayer *pSndPlayer);
+
+	void addSndEmitter(CSoundEmitter *pSndEmitter, const char *szName);
+	void delSndEmitter(const CSoundEmitter *pSndEmitter);
+
+	//************************************************************************
+
+	//! соответствует ли описание (его критические элементы) аудио буфера первичному буферу
+	bool matchPrimaryLayer(const AudioRawDesc *pDesc);
+
+	void setStateLayers(SOUND_STATE state);
+	void setStateSounds(SOUND_STATE state);
+
+	SOUND_STATE m_state = SOUND_STATE_STOP;
+
+	bool m_isPlaying = false;
+
+	CSoundLayer *m_pParent = NULL;
+
+	IAudioBufferEx *m_pPrimaryBuffer = NULL;
+	CSoundSystem *m_pSoundSystem = NULL;
+
+	String m_sName = "";
+
+	typedef AssotiativeArray<String, CSoundLayer*> maplayer;
+	maplayer m_mapLayers;
+
+	typedef AssotiativeArray<String, CSoundPlayer*> mapsoundplayer;
+	mapsoundplayer m_mapSndPlayers;
+
+	typedef AssotiativeArray<String, CSoundEmitter*> mapsoundemitter;
+	mapsoundemitter m_mapSndEmitters;
+};
+
+#endif
diff --git a/source/xSound/SoundLoader.cpp b/source/xSound/SoundLoader.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..51039cbb13ce1e7d932c2a083fe8729cc0fe2799
--- /dev/null
+++ b/source/xSound/SoundLoader.cpp
@@ -0,0 +1,57 @@
+
+#include "SoundLoader.h"
+
+#include "SoundSystem.h"
+
+//##########################################################################
+
+bool CSoundLoader::can() const
+{
+	return (bool)m_pCodecTarget;
+}
+
+void CSoundLoader::init(CSoundSystem *pSoundSystem)
+{
+	m_pSoundSystem = pSoundSystem;
+}
+
+bool CSoundLoader::load(const char *szPath, AudioRawDesc *pDesc)
+{
+	if (!m_pSoundSystem)
+		return false;
+
+	m_pCodecTarget = m_pSoundSystem->getCodecTarget(szPath);
+	if (!m_pCodecTarget)
+		return false;
+
+	m_pCodecTarget->getDesc(pDesc);
+
+	return true;
+}
+
+size_t CSoundLoader::getPCM(void **ppData, uint32_t uLen, int32_t iPos)
+{
+	if (!can())
+		return 0;
+
+	if (iPos < 0)
+		iPos = getPos();
+
+	return m_pCodecTarget->decode(iPos, uLen, ppData);
+}
+
+void CSoundLoader::setPos(uint32_t uPos)
+{
+	if (!can())
+		return;
+
+	m_pCodecTarget->setPos(uPos);
+}
+
+int32_t CSoundLoader::getPos() const
+{
+	if (!can())
+		return 0;
+
+	return m_pCodecTarget->getPos();
+}
diff --git a/source/xSound/SoundLoader.h b/source/xSound/SoundLoader.h
new file mode 100644
index 0000000000000000000000000000000000000000..6372307387125f716ca48cd01a13414bd9a154cf
--- /dev/null
+++ b/source/xSound/SoundLoader.h
@@ -0,0 +1,75 @@
+/*****************************************************
+Copyright © DogmaNet Team, 2020
+Site: dogmanet.ru
+See the license in LICENSE
+*****************************************************/
+
+#ifndef __SOUNDLOADER_H
+#define __SOUNDLOADER_H
+
+#include <common/string.h>
+
+#include "SoundTypes.h"
+
+//##########################################################################
+
+//! количество частей буфера потоковой загрузки
+#define STREAM_DATA_COUNT_PARTS 4
+
+//! минимальное количество частей для потоковой загрузки, чтобы была выбрана потоковая загрузка
+#define STREAM_COUNT_MIN_PARTS 100
+
+//! структура данных для потоковой загрузки
+struct CStreamData
+{
+	//! сколько частей уже проиграно (для определения позиции в звуке)
+	uint32_t uCountPlayed = 0;
+
+	//! размер одной части в байтах
+	uint32_t uPartSize = 0;
+
+	//! структура части
+	struct CPart
+	{
+		uint32_t uStart = 0;		//!< стартовая позиция
+		uint32_t uEnd = 0;			//!< конечная позиция
+		bool isPlay = false;		//!< воспроизводится ли сейчас часть
+		bool isLoaded = false;	//!< загружена ли эта часть
+	};
+
+	//! массив частей
+	CPart aParts[STREAM_DATA_COUNT_PARTS];
+
+	struct CRawData
+	{
+		BYTE *pData = 0;
+		uint32_t uSize = 0;
+	} oData;
+};
+
+//##########################################################################
+
+class CSoundLoader
+{
+public:
+	~CSoundLoader(){}
+
+	void init(CSoundSystem *pSoundSystem);
+
+	/*! загружает звук через подходящий декодер
+	*/
+	bool load(const char *szPath, AudioRawDesc *pDesc);
+	size_t getPCM(void **ppData, uint32_t uLen, int32_t iPos = -1);
+	void setPos(uint32_t uPos);
+	int32_t getPos() const;
+
+protected:
+
+	bool can() const;
+	IXAudioCodecTarget *m_pCodecTarget = NULL;
+	CSoundSystem *m_pSoundSystem = NULL;
+
+	String m_sPath = "";
+};
+
+#endif
diff --git a/source/xSound/SoundPlayer.cpp b/source/xSound/SoundPlayer.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..648532c1f5d6e717bd6bd460971b7e6b31ed49a4
--- /dev/null
+++ b/source/xSound/SoundPlayer.cpp
@@ -0,0 +1,313 @@
+
+#include "SoundPlayer.h"
+
+#include "SoundLoader.h"
+#include "SoundLayer.h"
+
+//##########################################################################
+
+CSoundPlayer::~CSoundPlayer()
+{
+	m_pLayer->delSndPlayer(this);
+	mem_release_del(m_pAB);
+
+	mem_delete(m_pCodecTarget);
+	mem_delete(m_pStream);
+}
+
+//**************************************************************************
+
+CSoundPlayer* CSoundPlayer::newInstance()
+{
+	if (m_pStream)
+		return NULL;
+
+	CSoundPlayer *pPlayer = new CSoundPlayer();
+
+	pPlayer->m_pAB = m_pAB->newInstance();
+	pPlayer->m_uLengthBytes = this->m_uLengthBytes;
+	pPlayer->m_fLengthMls = this->m_fLengthMls;
+	pPlayer->m_loop = this->m_loop;
+	pPlayer->m_dtype = this->m_dtype;
+	pPlayer->m_state = SOUND_STATE_STOP;
+	pPlayer->m_sName = this->m_sName;
+	pPlayer->m_pLayer = this->m_pLayer;
+	pPlayer->m_fDist = this->m_fDist;
+	pPlayer->m_vWorldPos = this->m_vWorldPos;
+	return pPlayer;
+}
+
+//**************************************************************************
+
+bool CSoundPlayer::create(CSoundLayer *pLayer, IXAudioCodecTarget *pCodecTarget, SOUND_DTYPE dtype)
+{
+	if (!pCodecTarget || !pLayer)
+		return false;
+
+	m_dtype = dtype;
+	m_pLayer = pLayer;
+	m_pCodecTarget = pCodecTarget;
+	AudioRawDesc oDesc;
+	pCodecTarget->getDesc(&oDesc);
+	m_uLengthBytes = oDesc.uSize;
+	m_fLengthMls = (uint32_t)(double(oDesc.uSize * 1000) / double(oDesc.uBytesPerSec));
+	
+	uint32_t uChunkSize = m_pLayer->getStreamChunkSize(&oDesc);
+
+
+	if (oDesc.uSize / uChunkSize > STREAM_COUNT_MIN_PARTS)
+	{
+		oDesc.uSize = uChunkSize * 4;
+		m_pAB = m_pLayer->createAudioBuffer(AB_TYPE_SECOND, &oDesc);
+		m_pStream = new CStreamData();
+		m_pStream->uPartSize = oDesc.uSize / STREAM_DATA_COUNT_PARTS;
+		m_pStream->oData.uSize = m_pStream->uPartSize;
+		m_pStream->oData.pData = new BYTE[m_pStream->oData.uSize];
+		for (int i = 0; i < STREAM_DATA_COUNT_PARTS; ++i)
+		{
+			m_pStream->aParts[i].uStart = i * m_pStream->uPartSize;
+			m_pStream->aParts[i].uEnd = m_pStream->aParts[i].uStart + m_pStream->uPartSize;
+		}
+		m_pAB->setLoop(AB_LOOP_SIMPLE);
+	}
+	else
+	{
+		m_pAB = m_pLayer->createAudioBuffer(AB_TYPE_SECOND, &oDesc);
+		BYTE *pData = new BYTE[oDesc.uSize];
+		m_pCodecTarget->decode(0, oDesc.uSize, (void**)&pData);
+
+		BYTE *pData2;
+		m_pAB->lock(AB_LOCK_WRITE, (void**)&pData2);
+		memcpy(pData2, pData, oDesc.uSize);
+		m_pAB->unlock();
+
+		mem_delete_a(pData);
+	}
+
+	setTime(0);
+
+	return true;
+}
+
+//##########################################################################
+
+void XMETHODCALLTYPE CSoundPlayer::play()
+{
+	if (!m_pLayer->isPlaying())
+		return;
+
+	float3 vPos, vLook, vUp;
+	m_pLayer->getObserverParam(&vPos, &vLook, &vUp);
+
+	Com3D(m_pAB, m_fDist, m_vWorldPos, vPos, vLook, vUp);
+	m_pAB->play(true);
+	m_state = SOUND_STATE_PLAY;
+}
+
+//**************************************************************************
+
+void XMETHODCALLTYPE CSoundPlayer::resume()
+{
+	if (!m_pLayer->isPlaying() || m_state != SOUND_STATE_PAUSE)
+		return;
+
+	m_pAB->play(true);
+}
+
+//**************************************************************************
+
+void XMETHODCALLTYPE CSoundPlayer::pause()
+{
+	m_pAB->play(false);
+	m_state = SOUND_STATE_PAUSE;
+}
+
+//**************************************************************************
+
+void XMETHODCALLTYPE CSoundPlayer::stop()
+{
+	m_pAB->play(false);
+	setTime(0.f);
+	m_state = SOUND_STATE_STOP;
+}
+
+//**************************************************************************
+
+bool XMETHODCALLTYPE CSoundPlayer::isPlaying() const
+{
+	return m_pAB->isPlaying();
+}
+
+//##########################################################################
+
+void XMETHODCALLTYPE CSoundPlayer::setLoop(SOUND_LOOP loop)
+{
+	m_loop = loop;
+	if (!m_pStream)
+		m_pAB->setLoop((AB_LOOP)m_loop);
+}
+
+//**************************************************************************
+
+SOUND_LOOP XMETHODCALLTYPE CSoundPlayer::getLoop() const
+{
+	return m_loop;
+}
+
+//##########################################################################
+
+float XMETHODCALLTYPE CSoundPlayer::getTime() const
+{
+	uint32_t uPos = getPosBytes();
+
+	if (m_pStream)
+	{
+		AudioRawDesc oDesc;
+		m_pAB->getDesc(&oDesc);
+		uPos = (uint64_t(uPos) * uint64_t(1000)) / uint64_t(oDesc.uBytesPerSec);
+	}
+
+	return float(uPos) / 1000.f;
+}
+
+//**************************************************************************
+
+void XMETHODCALLTYPE CSoundPlayer::setTime(float fTime)
+{
+	AudioRawDesc oDesc;
+	m_pAB->getDesc(&oDesc);
+	uint32_t uPosBytes = (uint64_t(fTime * 1000.f) * uint64_t(oDesc.uBytesPerSec)) / uint64_t(1000);
+
+	if (m_uLengthBytes < uPosBytes)
+		return;
+
+	if (m_pStream)
+		setPosStream(uPosBytes);
+	else
+		m_pAB->setPos(uPosBytes);
+}
+
+//**************************************************************************
+
+float XMETHODCALLTYPE CSoundPlayer::getLength() const
+{
+	return double(m_fLengthMls) / 1000.f;
+}
+
+//##########################################################################
+
+void CSoundPlayer::setPosStream(uint32_t uPos)
+{
+	uint32_t uCountParts = STREAM_DATA_COUNT_PARTS;
+	uint32_t uParts = uPos / (m_pStream->uPartSize * uCountParts);
+	if (uParts * m_pStream->uPartSize * uCountParts > uPos)
+		--uParts;
+
+	uint32_t uPosAB = (uPos - (uParts * m_pStream->uPartSize * uCountParts));
+	uint32_t uCurrPart = uPosAB / m_pStream->uPartSize;
+	m_pStream->uCountPlayed = uParts * uCountParts + uCurrPart;
+
+	uint32_t uPosLoader = uPos - (uCurrPart * m_pStream->uPartSize);
+	m_pCodecTarget->setPos(uPosLoader);
+	for (int i = 0; i < STREAM_DATA_COUNT_PARTS; ++i)
+	{
+		if (i >= uCurrPart)
+		{
+			size_t sizeRead = m_pCodecTarget->decode(m_pCodecTarget->getPos(), m_pStream->oData.uSize, (void**)&(m_pStream->oData.pData));
+			if (sizeRead <= 0)
+				continue;
+
+			BYTE *pData = 0;
+			uint32_t uLocked = m_pAB->lock(AB_LOCK_WRITE, (void**)&pData, m_pStream->aParts[i].uStart, m_pStream->aParts[i].uEnd - m_pStream->aParts[i].uStart);
+			memcpy(pData, m_pStream->oData.pData, sizeRead);
+			m_pAB->unlock();
+
+			m_pStream->aParts[i].isLoaded = true;
+		}
+		else
+		{
+			m_pStream->aParts[i].isPlay = false;
+			m_pStream->aParts[i].isLoaded = false;
+		}
+	}
+
+	int qwerty = 0;
+}
+
+//**************************************************************************
+
+uint32_t CSoundPlayer::getPosBytes() const
+{
+	uint32_t uPos = m_pAB->getPos();
+
+	if (m_pStream)
+		uPos = (uint64_t(uPos) + uint64_t(m_pStream->uPartSize) * uint64_t(m_pStream->uCountPlayed));
+
+	return uPos;
+}
+
+//##########################################################################
+
+void CSoundPlayer::update(const float3 &vListenerPos, const float3 &vListenerDir, const float3 &vListenerUp)
+{
+	if (!m_pLayer->isPlaying())
+		return;
+
+	if (m_dtype == SOUND_DTYPE_3D)
+	{
+		Com3D(m_pAB, m_fDist, m_vWorldPos, vListenerPos, vListenerDir, vListenerUp);
+	}
+
+	if (!m_pStream)
+		return;
+
+	uint32_t uGPosBytes = getPosBytes();
+	uint32_t uGPosBytes2 = m_pCodecTarget->getPos();
+
+	/*static uint32_t uMax = 0;
+	if (uMax < uGPosBytes)
+	{
+		uMax = uGPosBytes;
+		printf("uMax = %d\n", uMax);
+	}*/
+
+	if (uGPosBytes >= m_uLengthBytes)
+	{
+		if (m_loop == AB_LOOP_NONE)
+			m_pAB->play(false);
+		else
+			setTime(0.f);
+	}
+
+	if (!isPlaying())
+		return;
+
+	uint32_t uPos = m_pAB->getPos();
+
+	for (int i = 0; i < STREAM_DATA_COUNT_PARTS; ++i)
+	{
+		if (m_pStream->aParts[i].uStart <= uPos && uPos <= m_pStream->aParts[i].uEnd)
+			m_pStream->aParts[i].isPlay = true;
+		else
+		{
+			if (m_pStream->aParts[i].isPlay)
+			{
+				m_pStream->aParts[i].isPlay = false;
+				m_pStream->aParts[i].isLoaded = false;
+
+				size_t sizeRead = m_pCodecTarget->decode(m_pCodecTarget->getPos(), m_pStream->oData.uSize, (void**)&(m_pStream->oData.pData));
+				++(m_pStream->uCountPlayed);
+				if (sizeRead == 0)
+					continue;
+
+				BYTE *pData = 0;
+				uint32_t uLocked = m_pAB->lock(AB_LOCK_WRITE, (void**)&pData, m_pStream->aParts[i].uStart, m_pStream->aParts[i].uEnd - m_pStream->aParts[i].uStart);
+				memset(pData, 0, uLocked);
+				memcpy(pData, m_pStream->oData.pData, sizeRead);
+				m_pAB->unlock();
+
+				m_pStream->aParts[i].isLoaded = true;
+			}
+		}
+	}
+}
diff --git a/source/xSound/SoundPlayer.h b/source/xSound/SoundPlayer.h
new file mode 100644
index 0000000000000000000000000000000000000000..e21098dd48cc669deb91af4c154e82a1a99af274
--- /dev/null
+++ b/source/xSound/SoundPlayer.h
@@ -0,0 +1,80 @@
+/*****************************************************
+Copyright © DogmaNet Team, 2020
+Site: dogmanet.ru
+See the license in LICENSE
+*****************************************************/
+
+#ifndef __SOUNDPLAYER_H
+#define __SOUNDPLAYER_H
+
+#include <xcommon/IXSoundSystem.h>
+#include "SoundBase.h"
+#include <mital.h>
+
+#include "SoundTypes.h"
+#include "SoundSystem.h"
+
+//##########################################################################
+
+class CSoundPlayer : public CSoundBase, public virtual IXSoundPlayer
+{
+public:
+	SX_ALIGNED_OP_MEM
+
+		~CSoundPlayer();
+
+	CSoundPlayer* newInstance();
+
+	virtual void XMETHODCALLTYPE play() override;
+	virtual void XMETHODCALLTYPE resume() override;
+	virtual void XMETHODCALLTYPE pause() override;
+	virtual void XMETHODCALLTYPE stop() override;
+
+	virtual bool XMETHODCALLTYPE isPlaying() const override;
+
+	virtual SOUND_LOOP XMETHODCALLTYPE getLoop() const override;
+	virtual void XMETHODCALLTYPE setLoop(SOUND_LOOP loop) override;
+
+	virtual float XMETHODCALLTYPE getTime() const override;
+	virtual void XMETHODCALLTYPE setTime(float fTime) override;
+
+	virtual float XMETHODCALLTYPE getLength() const override;
+
+protected:
+
+	friend CSoundLayer;
+
+	void update(const float3 &vListenerPos, const float3 &vListenerDir, const float3 &vListenerUp);
+
+	bool create(CSoundLayer *pLayer, IXAudioCodecTarget *pCodecTarget, SOUND_DTYPE dtype);
+
+	//! возвращает текущую позицию проигрывания звука в байтах
+	uint32_t getPosBytes() const;
+
+	/*! установка позиции при потоковом воспроизведении
+		@param uPos позиция в байтах
+	*/
+	void setPosStream(uint32_t uPos);
+
+	//************************************************************************
+
+	//! аудио буфер
+	IAudioBuffer *m_pAB = NULL;
+
+	//! зацикливать ли воспроизведение
+	SOUND_LOOP m_loop = SOUND_LOOP_NONE;
+
+	//! длина звука в байтах
+	uint32_t m_uLengthBytes = 0;
+
+	//! длина звука в секундах
+	uint32_t m_fLengthMls = 0;
+
+	//! кодек
+	IXAudioCodecTarget *m_pCodecTarget = NULL;
+
+	//! данные потоковой загрузки
+	CStreamData *m_pStream = NULL;
+};
+
+#endif
diff --git a/source/xSound/SoundSystem.cpp b/source/xSound/SoundSystem.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7109a7ce15a4cd4ce9788905557b132c430b1acd
--- /dev/null
+++ b/source/xSound/SoundSystem.cpp
@@ -0,0 +1,294 @@
+
+#include "SoundSystem.h"
+#include "AudioConverter.h"
+
+#include "SoundLayer.h"
+
+#include <ctime>
+#include <sys/stat.h>
+
+#ifdef _MSC_VER
+#include <direct.h>
+#endif
+
+//##########################################################################
+
+CSoundSystem::CSoundSystem(IXCore *pXCore)
+{
+#ifdef _MSC_VER
+	mkdir(SOUND_CACHE);
+#else
+	mkdir(SOUND_CACHE, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
+#endif
+
+	m_pXCore = pXCore;
+
+	auto pPluginManager = m_pXCore->getPluginManager();
+
+	IXAudioCodec *pAudioCodec;
+	UINT ic = 0;
+	while ((pAudioCodec = (IXAudioCodec*)(pPluginManager->getInterface(IXAUDIOCODEC_GUID, ic++))))
+	{
+		if (pAudioCodec->getVersion() == IXAUDIOCODEC_VERSION)
+		{
+			LibReport(REPORT_MSG_LEVEL_NOTICE, "Registered audio codec: %s\n", pAudioCodec->getFormat());
+
+			addCodec(pAudioCodec->getFormat(), pAudioCodec);
+		}
+	}
+
+	m_pAudio = MitAl_InitAudio();
+}
+
+CSoundSystem::~CSoundSystem()
+{
+	mem_release(m_pMasterLayer);
+}
+
+//**************************************************************************
+
+void XMETHODCALLTYPE CSoundSystem::update(const float3 &vListenerPos, const float3 &vListenerDir, const float3 &vListenerUp)
+{
+	std::lock_guard<std::mutex> guard(m_oMutexUpdate);
+
+	if(m_pMasterLayer)
+		m_pMasterLayer->update(vListenerPos, vListenerDir, vListenerUp);
+
+	m_vObserverPos = vListenerPos; m_vObserverLook = vListenerDir; m_vObserverUp = vListenerUp;
+}
+
+//**************************************************************************
+
+IXSoundLayer* XMETHODCALLTYPE CSoundSystem::createMasterLayer(const AudioRawDesc *pDesc, const char *szName)
+{
+	if(m_pMasterLayer)
+		return m_pMasterLayer;
+
+	if(!pDesc)
+		return NULL;
+
+	if (!supportedDesc(pDesc, AB_TYPE_PRIMARY))
+	{
+		printf("unsupported audio buffer description");
+		return NULL;
+	}
+
+	CSoundLayer *pLayer = new CSoundLayer();
+	pLayer->init(this, NULL, pDesc, szName);
+
+	m_pMasterLayer = pLayer;
+
+	return pLayer;
+}
+
+//**************************************************************************
+
+IXCore* CSoundSystem::getCore() const
+{
+	return m_pXCore;
+}
+
+//**************************************************************************
+
+IXAudioCodecTarget* CSoundSystem::getCodecTarget(const char *szName)
+{
+	if(!m_pMasterLayer)
+		return NULL;
+
+	if (!szName)
+		return NULL;
+
+	const char *szPath = szName;
+
+	if (!m_pXCore->getFileSystem()->fileExists(szPath))
+	{
+		LibReport(REPORT_MSG_LEVEL_ERROR, "File '%s' not found\n", szPath);
+		return NULL;
+	}
+
+	IXAudioCodec *pCodec = NULL;
+	IXAudioCodecTarget *pTarget = NULL;
+	IXAudioCodecTarget *pTarget2 = NULL;
+
+	for (mapcodec::Iterator i = m_mapCodecs.begin(); i != m_mapCodecs.end(); i++)
+	{
+		if (m_mapCodecs[i.first]->open(szPath, "", &pTarget, false))
+		{
+			pCodec = m_mapCodecs[i.first];
+			break;
+		}
+	}
+
+	if(!pCodec || !pTarget)
+	{
+		LibReport(REPORT_MSG_LEVEL_ERROR, "Unsupported audio format '%s'\n", szPath);
+		return NULL;
+	}
+
+	AudioRawDesc oDescMaster, oDescSnd, oDescCache;
+	m_pMasterLayer->getDesc(&oDescMaster);
+	pTarget->getDesc(&oDescSnd);
+
+	//если звук соответствует требования мастер буфера, тогда не надо конвертировать, возвращает целевой кодек
+	if(oDescSnd.uSampleRate == oDescMaster.uSampleRate)
+		return pTarget;
+
+
+	//если кодек может сохранять, тогда пересохраняем файл
+	if(pCodec->canSave())
+	{
+		//выдергиваем pcm данные из таргета и удаляем его
+		IXBuffer *pBufferIn = m_pXCore->newBuffer();
+		IXBuffer *pBufferOut = m_pXCore->newBuffer();
+		pBufferIn->alloc(oDescSnd.uSize);
+		BYTE *pData = pBufferIn->get();
+		pTarget->decode(0, pBufferIn->size(), (void**)&pData);
+		pTarget->Release();
+
+		//открываем файл на запись
+		if(!pCodec->open(szPath, "", &pTarget, true))
+			return NULL;
+
+		//создаем нужное описание и конвертируем pcm данные
+		AudioRawDesc oDescOut = oDescSnd;
+		oDescOut.uSampleRate = oDescMaster.uSampleRate;
+		oDescOut.calc();
+		if (!AudioConverter(pData, &oDescSnd, pBufferOut, &oDescOut))
+			return NULL;
+
+		//записываем новые данные и сносим таргет
+		pTarget->encode(pBufferOut, &oDescOut);
+		pTarget->Release();
+
+		//открываем файл на чтение
+		if(!pCodec->open(szPath, "", &pTarget, false))
+			return NULL;
+
+		return pTarget;
+	}
+
+	//ищем первый попавшийся кодек который может записывать
+	IXAudioCodec *pFullCodec = getCodecSave();
+	if (!pFullCodec)
+	{
+		LibReport(REPORT_MSG_LEVEL_ERROR, "Not found codec for coding, file '%s' does not match of parameters master buffer\n", szPath);
+		return NULL;
+	}
+
+	//создаем путь до файла в кэше
+	String sCachePath = String(SOUND_CACHE) + "/"+ szPath;
+	sCachePath = PathSetExt(sCachePath.c_str(), pFullCodec->getExt());
+
+	//берем инфу о файлах (оригинал и кэш)
+	struct stat stOrigin, stCache;
+	stat(szPath, &stOrigin);
+	stat(sCachePath.c_str(), &stCache);
+
+	//нужно ли конвертировать файл
+	bool canConvert = false;
+
+	//если есть разница по времени (изменения/модификации), тогда надо конвертировать
+#ifdef _MSC_VER
+	if (stOrigin.st_ctime > stCache.st_ctime || stOrigin.st_mtime > stCache.st_mtime)
+#else
+	if(stOrigin.st_ctim.tv_sec > stCache.st_ctim.tv_sec || stOrigin.st_mtim.tv_sec > stCache.st_mtim.tv_sec)
+#endif
+		canConvert = true;
+	else
+	{
+		//если не удается открыть файл кэша, то надо конвертировать
+		if(!pFullCodec->open(sCachePath.c_str(), "", &pTarget2, false))
+			canConvert = true;
+		else
+		{
+			//если файл кэша не соответствует, тогда надо конвертировать
+			pTarget2->getDesc(&oDescCache);
+			if(oDescCache.uSampleRate != oDescMaster.uSampleRate)
+				canConvert = true;
+		}
+	}
+
+	//если конвертирование не требуется, возвращаем целевой кодек
+	if(!canConvert)
+		return pTarget2;
+
+	mem_release(pTarget2);
+
+	//выдергиваем pcm данные из таргета и удаляем его
+	IXBuffer *pBufferIn = m_pXCore->newBuffer();
+	IXBuffer *pBufferOut = m_pXCore->newBuffer();
+	pBufferIn->alloc(oDescSnd.uSize);
+	BYTE *pData = pBufferIn->get();
+	pTarget->decode(0, pBufferIn->size(), (void**)&pData);
+	pTarget->Release();
+
+	//создаем нужное описание и конвертируем pcm данные
+	AudioRawDesc oDescOut = oDescSnd;
+	oDescOut.uSampleRate = oDescMaster.uSampleRate;
+	oDescOut.calc();
+	if (!AudioConverter(pData, &oDescSnd, pBufferOut, &oDescOut))
+		return NULL;
+
+	//открываем файл на запись
+	if(!pFullCodec->open(sCachePath.c_str(), "", &pTarget2, true))
+		return NULL;
+
+	pTarget2->encode(pBufferOut, &oDescOut);
+	pTarget2->Release();
+
+	if(!pFullCodec->open(sCachePath.c_str(), "", &pTarget2, false))
+		return NULL;
+
+	return pTarget2;
+}
+
+//**************************************************************************
+
+void CSoundSystem::addCodec(const char *szFmt, IXAudioCodec *pCodec)
+{
+	if(!szFmt || !pCodec)
+		return;
+
+	m_mapCodecs[szFmt] = pCodec;
+}
+
+//**************************************************************************
+
+IAudioBufferEx* CSoundSystem::createMasterBuffer(AudioRawDesc *pDesc)
+{
+	return m_pAudio->createMasterBuffer(pDesc);
+}
+
+//**************************************************************************
+
+bool CSoundSystem::supportedDesc(const AudioRawDesc *pDesc, AB_TYPE type)
+{
+	return m_pAudio->supportedDesc(pDesc, type);
+}
+
+//**************************************************************************
+
+IXSoundLayer* XMETHODCALLTYPE CSoundSystem::findLayer(const char *szName)
+{
+	if(!szName)
+		return NULL;
+
+	if(strcasecmp(m_pMasterLayer->getName(), szName) == 0)
+		return m_pMasterLayer;
+
+	return m_pMasterLayer->findLayer(szName);
+}
+
+//**************************************************************************
+
+IXAudioCodec* CSoundSystem::getCodecSave()
+{
+	for (mapcodec::Iterator i = m_mapCodecs.begin(); i != m_mapCodecs.end(); i++)
+	{
+		if (m_mapCodecs[i.first]->canSave())
+			return m_mapCodecs[i.first];
+	}
+
+	return NULL;
+}
+
diff --git a/source/xSound/SoundSystem.h b/source/xSound/SoundSystem.h
new file mode 100644
index 0000000000000000000000000000000000000000..62ffad2c74decfb24ee6ee4cfe48bf59e99c00cc
--- /dev/null
+++ b/source/xSound/SoundSystem.h
@@ -0,0 +1,95 @@
+/*****************************************************
+Copyright © DogmaNet Team, 2020
+Site: dogmanet.ru
+See the license in LICENSE
+*****************************************************/
+
+#ifndef __SOUNDSYSTEM_H
+#define __SOUNDSYSTEM_H
+
+#include <common/assotiativearray.h>
+#include <common/string.h>
+#include <common/path_utils.h>
+#include <common/math.h>
+
+#include <xcommon/IXCore.h>
+#include <xcommon/IPluginManager.h>
+#include <xcommon/IXSoundSystem.h>
+#include <xcommon/IXAudioCodec.h>
+
+#include "SoundTypes.h"
+
+//##########################################################################
+
+inline float Com3DPan(const float3 &vSnd, const float3 &vListenerPos, const float3 &vListenerDir, const float3 &vListenerUp)
+{
+	float3 side = SMVector3Cross(vListenerUp, vListenerDir);
+	SMVector3Normalize(side);
+	float x = SMVector3Dot(vSnd - vListenerPos, side);
+	float z = SMVector3Dot(vSnd - vListenerPos, vListenerDir);
+	float angle = atan2(x, z);
+	float pan = sin(angle);
+	return pan;
+}
+
+inline void Com3D(IAudioBuffer *pAB, float fDist, const float3 &vSnd, const float3 &vListenerPos, const float3 &vListenerDir, const float3 &vListenerUp)
+{
+	float fPan = Com3DPan(vSnd, vListenerPos, vListenerDir, vListenerUp);
+	float fVolume = 1.f - saturatef(SMVector3Distance(vSnd, vListenerPos) / fDist);
+	fPan = lerpf(fPan, 0.f, fVolume);
+	pAB->setPan(fPan);
+	pAB->setVolume(fVolume);
+}
+
+//##########################################################################
+
+class CSoundSystem: public IXUnknownImplementation<IXSoundSystem>
+{
+public:
+	SX_ALIGNED_OP_MEM
+
+	CSoundSystem(IXCore *pXCore);
+	~CSoundSystem();
+
+	virtual IXSoundLayer* XMETHODCALLTYPE createMasterLayer(const AudioRawDesc *pDesc, const char *szName) override;
+	virtual IXSoundLayer* XMETHODCALLTYPE findLayer(const char *szName) override;
+
+	virtual void XMETHODCALLTYPE update(const float3 &vListenerPos, const float3 &vListenerDir, const float3 &vListenerUp) override;
+
+	IXAudioCodecTarget* getCodecTarget(const char *szName);
+
+	IXCore* getCore() const;
+
+	void getObserverParam(float3 *pPos, float3 *pLook, float3 *pUp)
+	{
+		while (!m_oMutexUpdate.try_lock()){}
+		m_oMutexUpdate.unlock();
+		
+		*pPos = m_vObserverPos; *pLook = m_vObserverLook; *pUp = m_vObserverUp;
+	}
+
+protected:
+
+	friend CSoundLayer;
+
+	IAudioBufferEx* createMasterBuffer(AudioRawDesc *pDesc);
+	bool supportedDesc(const AudioRawDesc *pDesc, AB_TYPE type);
+
+	void addCodec(const char *szFmt, IXAudioCodec *pCodec);
+
+	IXCore *m_pXCore = NULL;
+
+	IAudio *m_pAudio = NULL;
+
+	IXAudioCodec* getCodecSave();
+
+	CSoundLayer *m_pMasterLayer = NULL;
+
+	typedef AssotiativeArray<String, IXAudioCodec*> mapcodec;
+	mapcodec m_mapCodecs;
+
+	float3 m_vObserverPos, m_vObserverLook, m_vObserverUp;
+	std::mutex m_oMutexUpdate;
+};
+
+#endif
diff --git a/source/xSound/SoundTypes.h b/source/xSound/SoundTypes.h
new file mode 100644
index 0000000000000000000000000000000000000000..5c4c77482db1e05e86c2ac643c665f889cb21def
--- /dev/null
+++ b/source/xSound/SoundTypes.h
@@ -0,0 +1,37 @@
+/*****************************************************
+Copyright © DogmaNet Team, 2020
+Site: dogmanet.ru
+See the license in LICENSE
+*****************************************************/
+
+#ifndef __SOUNDTYPES_H
+#define __SOUNDTYPES_H
+
+#include <xcommon/IXSoundSystem.h>
+#include <xcommon/IXAudioCodec.h>
+
+#include <mital.h>
+
+//##########################################################################
+
+class CStreamData;
+
+class CSoundBase;
+class CSoundLoader;
+class CSoundEmitter;
+class CSoundPlayer;
+class CSoundLayer;
+class CSoundSystem;
+
+//##########################################################################
+
+//! состояния воспроизведения звукового объекта
+enum SOUND_STATE
+{
+	SOUND_STATE_STOP,		//!< остановлен
+	SOUND_STATE_PAUSE,	//!< приостановлен
+	SOUND_STATE_PLAY,		//!< проигрывается
+};
+
+
+#endif
\ No newline at end of file
diff --git a/source/xSound/dllmain.cpp b/source/xSound/dllmain.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..fdece5b079edcec13c692b45e9101170ba1093d4
--- /dev/null
+++ b/source/xSound/dllmain.cpp
@@ -0,0 +1,24 @@
+
+/***********************************************************
+Copyright � Vitaliy Buturlin, Evgeny Danilovich, 2017, 2018
+See the license in LICENSE
+***********************************************************/
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+BOOL APIENTRY DllMain(HMODULE hModule,
+	DWORD  ul_reason_for_call,
+	LPVOID lpReserved
+	)
+{
+	switch(ul_reason_for_call)
+	{
+	case DLL_PROCESS_ATTACH:
+	case DLL_THREAD_ATTACH:
+	case DLL_THREAD_DETACH:
+	case DLL_PROCESS_DETACH:
+		break;
+	}
+	return TRUE;
+}
diff --git a/source/xSound/plugin_main.cpp b/source/xSound/plugin_main.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f21f993d4857a09e75dac5bd9dccbc1f9032b3f3
--- /dev/null
+++ b/source/xSound/plugin_main.cpp
@@ -0,0 +1,173 @@
+
+#include <xcommon/IXPlugin.h>
+#include <xcommon/IXUpdatable.h>
+#include "SoundSystem.h"
+#include <Audio.h>
+#include <gcore/sxgcore.h>
+
+#if defined(_DEBUG)
+#pragma comment(lib, "mital_d.lib")
+#else
+#pragma comment(lib, "mital.lib")
+#endif
+
+//##########################################################################
+
+class CObserverChangedEventListener : public IEventListener<XEventObserverChanged>
+{
+public:
+	SX_ALIGNED_OP_MEM
+
+	CObserverChangedEventListener(IXCore *pCore)
+	{
+		m_pObserverChangedEventChannel = pCore->getEventChannel<XEventObserverChanged>(EVENT_OBSERVER_CHANGED_GUID);
+		m_pObserverChangedEventChannel->addListener(this);
+	}
+
+	~CObserverChangedEventListener()
+	{
+		m_pObserverChangedEventChannel->removeListener(this);
+	}
+
+	void onEvent(const XEventObserverChanged *pData) override
+	{
+		std::lock_guard<std::mutex> guard(m_oMutex);
+		pData->pCamera->getPosition(&m_vPos);
+		pData->pCamera->getUp(&m_vUp);
+		pData->pCamera->getLook(&m_vLook);
+	}
+
+	void getObserverParam(float3 *pPos, float3 *pLook, float3 *pUp)
+	{
+		std::lock_guard<std::mutex> guard(m_oMutex);
+		*pPos = m_vPos; *pLook = m_vLook; *pUp = m_vUp;
+	}
+
+protected:
+	IEventChannel<XEventObserverChanged> *m_pObserverChangedEventChannel = NULL;
+	float3 m_vPos, m_vLook, m_vUp;
+	std::mutex m_oMutex;
+};
+
+//##########################################################################
+
+class CUpdatableSoundSystem : public IXUnknownImplementation<IXUpdatable>
+{
+public:
+	SX_ALIGNED_OP_MEM
+
+	CUpdatableSoundSystem(CSoundSystem *pSoundSystem, CObserverChangedEventListener *pObserverListener)
+	{
+		m_pSoundSystem = pSoundSystem;
+		m_pObserverListener = pObserverListener;
+	}
+
+	UINT startup() override
+	{
+		return 1;
+	}
+	void shutdown() override
+	{
+		mem_release(m_pSoundSystem);
+	}
+
+	ID run(float fDelta) override
+	{
+		float3 vPos, vLook, vUp;
+
+		if (m_pObserverListener)
+			m_pObserverListener->getObserverParam(&vPos, &vLook, &vUp);
+
+		if (m_pSoundSystem)
+			m_pSoundSystem->update(vPos, vLook, vUp);
+
+		/*if (!m_pEmitter)
+		{
+			IXSoundLayer *pMasterLayer = m_pSoundSystem->findLayer("master");
+			if (pMasterLayer)
+			{
+				m_pEmitter = pMasterLayer->newSoundEmitter("sounds/ak74_shoot.ogg", SOUND_DTYPE_3D);
+				m_pEmitter->setWorldPos(float3(-11.084, 0.435, -18.707));
+				m_pEmitter->setDistance(50);
+				//pEmitter->play();
+			}
+		}
+		else
+		{
+			if (GetAsyncKeyState('I'))
+			{
+				m_pEmitter->play();
+				//Sleep(100);
+			}
+		}*/
+
+		return -1;
+	}
+
+	void sync() override
+	{
+
+	}
+
+protected:
+	CSoundSystem *m_pSoundSystem = NULL;
+	CObserverChangedEventListener *m_pObserverListener = NULL;
+	IXSoundEmitter *m_pEmitter = NULL;
+};
+
+//##########################################################################
+
+class CSoundSystemPlugin : public IXUnknownImplementation<IXPlugin>
+{
+public:
+
+	void XMETHODCALLTYPE startup(IXCore *pCore) override
+	{
+		m_pCore = pCore;
+		m_pSoundSystem = new CSoundSystem(m_pCore);
+		m_pObserverListener = new CObserverChangedEventListener(m_pCore);
+		m_pUpdatableSoundSystem = new CUpdatableSoundSystem(m_pSoundSystem, m_pObserverListener);
+	}
+
+	void XMETHODCALLTYPE shutdown() override
+	{
+	}
+
+	UINT XMETHODCALLTYPE getInterfaceCount() override
+	{
+		return(2);
+	}
+	const XGUID* XMETHODCALLTYPE getInterfaceGUID(UINT id) override
+	{
+		static XGUID s_guid;
+		switch(id)
+		{
+		case 0:
+			s_guid = IXSOUNDSYSTEM_GUID;
+			break;
+		case 1:
+			s_guid = IXUPDATABLE_GUID;
+			break;
+		default:
+			return(NULL);
+		}
+		return(&s_guid);
+	}
+	IXUnknown* XMETHODCALLTYPE getInterface(const XGUID &guid) override
+	{
+		if (guid == IXSOUNDSYSTEM_GUID)
+			return m_pSoundSystem;
+		else if (guid == IXUPDATABLE_GUID)
+			return m_pUpdatableSoundSystem;
+
+		return(NULL);
+	}
+
+protected:
+	IXCore *m_pCore;
+	CSoundSystem *m_pSoundSystem = NULL;
+	CUpdatableSoundSystem *m_pUpdatableSoundSystem = NULL;
+	CObserverChangedEventListener *m_pObserverListener = NULL;
+};
+
+DECLARE_XPLUGIN(CSoundSystemPlugin);
diff --git a/source/xcommon/XEvents.h b/source/xcommon/XEvents.h
index a3fbfc39dc08aa727498e90f3d0b99e5ce01a94e..0d33ec29ad8f0a288dbc3071444ff7d8ff0c1226 100644
--- a/source/xcommon/XEvents.h
+++ b/source/xcommon/XEvents.h
@@ -222,4 +222,14 @@ struct XEventCvarChanged
 	const void *pCvar;
 };
 
+
+// {5CEC2355-1F1E-4A1D-8E69-5B92850B62D2}
+#define EVENT_OBSERVER_CHANGED_GUID DEFINE_XGUID(0x5cec2355, 0x1f1e, 0x4a1d, 0x8e, 0x69, 0x5b, 0x92, 0x85, 0xb, 0x62, 0xd2)
+
+class ICamera;
+struct XEventObserverChanged
+{
+	ICamera *pCamera;
+};
+
 #endif
diff --git a/source/xcommon/resource/IXResourceManager.h b/source/xcommon/resource/IXResourceManager.h
index 37c30eb6b1873c52b57dfa8ef2161bfa7eb12717..30f20064c0a588b465d07b6bf82ceb12731ad777 100644
--- a/source/xcommon/resource/IXResourceManager.h
+++ b/source/xcommon/resource/IXResourceManager.h
@@ -45,6 +45,9 @@ public:
 	virtual IXResourceTexture2D* XMETHODCALLTYPE newResourceTexture2D() = 0;
 	virtual IXResourceTextureCube* XMETHODCALLTYPE newResourceTextureCube() = 0;
 	virtual void XMETHODCALLTYPE addTexture(const char *szName, IXResourceTexture *pTexture) = 0;
+
+	virtual UINT XMETHODCALLTYPE getSoundSupportedFormats() = 0;
+	virtual const XFormatName* XMETHODCALLTYPE getSoundSupportedFormat(UINT uIndex) = 0;
 };
 
 #endif