This commit is contained in:
McSchneidar authored and GitHub committed 2026-10-22 19:41:30 +02:00
1 parent 288c8631f0
commit 73a24ad930
18 files changed
+591 -668

No files matched your search

+8
View File
@@ -0,0 +1,8 @@
Copyright 2020 Mark Heath
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,7 @@
https://github.com/naudio/NAudio
Version: NAudio.Wasapi 2.2.1, NAudio.Core 2.2.1 (NuGet, netstandard2.0)
Files:
NAudio.Wasapi.dll
NAudio.Core.dll
-19
View File
@@ -1,19 +0,0 @@
Copyright (c) 2007-2012 SlimDX Group
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
@@ -1,7 +0,0 @@
http://slimdx.org/download.php
SVN r2171 (Feb 4, 2012) -> Equal to Jan 12 release but recompiled with VS2012
Files:
x86/SlimDx.dll
x64/SlimDx.dll
+48
View File
@@ -0,0 +1,48 @@
Vortice.Direct3D9, Vortice.Mathematics
MIT License
Copyright (c) Amer Koleci and Contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
----------------------------------------------------------------------
SharpGen.Runtime, SharpGen.Runtime.COM
MIT License
Copyright (c) 2010-2017 Alexandre Mutel, 2017-2018 Jeremy Koritzinsky
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
@@ -0,0 +1,12 @@
https://github.com/amerkoleci/Vortice.Windows
https://github.com/amerkoleci/Vortice.Mathematics
https://github.com/SharpGenTools/SharpGenTools
Version: Vortice.Direct3D9 2.4.2 (NuGet, netstandard2.0), Vortice.Mathematics 1.4.25,
SharpGen.Runtime 2.0.0-beta.13, SharpGen.Runtime.COM 2.0.0-beta.13
Files:
Vortice.Direct3D9.dll
Vortice.Mathematics.dll
SharpGen.Runtime.dll
SharpGen.Runtime.COM.dll
+5 -1
View File
@@ -26,7 +26,11 @@ Supported Operating Systems / Requirements:
- Windows 7, Windows 8, Windows 8.1, Windows 10 and Windows 11 with .NET 4.0
- Linux (no official support)
- 1 GHz CPU, 512 MB RAM, Graphics card with OpenGL 2.1 or DirectX 9.0 support
- Visual C++ Redistributable Package 2010 (Nightly builds additionally require VC++ 2015–2022)
- Visual C++ Redistributable Package 2010
Nightly Builds:
- Windows 10 (version 20H2 or later) and Windows 11 with .NET Framework 4.8.1
- Visual C++ Redistributable 2015–2022
=================================
+5 -1
View File
@@ -22,7 +22,11 @@ Supported Operating Systems / Requirements:
- Windows 7, Windows 8, Windows 8.1, Windows 10 and Windows 11 with .NET 4.0
- *Linux* (no official support)
- 1 GHz CPU, 512 MB RAM, Graphics card with OpenGL 2.1 or DirectX 9.0 support
- Visual C++ Redistributable Package 2010 (Nightly builds additionally require VC++ 2015–2022)
- Visual C++ Redistributable Package 2010
Nightly Builds:
- Windows 10 (version 20H2 or later) and Windows 11 with .NET Framework 4.8.1
- Visual C++ Redistributable 2015–2022
## 2. Download
+1 -2
View File
@@ -125,8 +125,7 @@ namespace Vocaluxe.Base
}
catch (Exception e)
{
CLog.Fatal(e, "Error in initializing of Direct3D. Please check if your DirectX redistributables and graphic card drivers are up to date. You can " +
"download the DirectX runtimes at https://www.microsoft.com/en-us/download/details.aspx?id=8109");
CLog.Fatal(e, "Error in initializing of Direct3D. Please check whether your graphic card drivers are up to date.");
return false;
}
+3 -3
View File
@@ -20,7 +20,7 @@ using Vocaluxe.Lib.Sound.Record;
using Vocaluxe.Lib.Sound.Record.PortAudio;
using VocaluxeLib;
#if WIN
using Vocaluxe.Lib.Sound.Record.DirectSound;
using Vocaluxe.Lib.Sound.Record.NAudio;
#endif
namespace Vocaluxe.Base
@@ -39,8 +39,8 @@ namespace Vocaluxe.Base
switch (CConfig.Config.Sound.RecordLib)
{
#if WIN
case ERecordLib.DirectSound:
_Record = new CDirectSoundRecord();
case ERecordLib.NAudio:
_Record = new CNAudioRecord();
break;
#endif
-71
View File
@@ -17,7 +17,6 @@
using System.IO;
using System.Reflection;
using System.Security;
using Microsoft.Win32;
using Vocaluxe.Base;
using VocaluxeLib.Log;
@@ -29,69 +28,6 @@ namespace Vocaluxe
/// </summary>
static class CProgrammHelper
{
private static bool _CheckUninstallKey(string name, string key)
{
using (var rk = Registry.LocalMachine.OpenSubKey(key))
{
if (rk == null)
{
throw new SecurityException();
}
foreach (var skName in rk.GetSubKeyNames())
{
using (var sk = rk.OpenSubKey(skName))
{
if (sk == null || sk.GetValue("DisplayName") == null)
{
continue;
}
var displayName = sk.GetValue("DisplayName").ToString().ToLower();
if (displayName.Equals(name) || displayName.StartsWith(name) || name.StartsWith(displayName))
{
return true;
}
}
}
}
return false;
}
private static bool _KeyExists(string key)
{
using (var rk = Registry.LocalMachine.OpenSubKey(key))
{
if (rk != null)
{
return true;
}
}
return false;
}
/// <summary>
/// Checks if a given program is installed by checking the Uninstall registry key.
/// </summary>
/// <param name="name">Name of the programm. Got to equal the displayname in the key or one needs to be the start of the other one. NOT case sensitive.</param>
/// <returns></returns>
private static bool _IsProgramInstalled(string name)
{
const string baseKey = @"SOFTWARE\";
const string baseKey64 = @"SOFTWARE\WoW6432Node\";
const string uninstallKey = @"Microsoft\Windows\CurrentVersion\Uninstall";
name = name.ToLower();
return _CheckUninstallKey(name, baseKey + uninstallKey) || (_KeyExists(baseKey64) && _CheckUninstallKey(name, baseKey64 + uninstallKey));
}
private static bool _IsVC2010Installed()
{
//Note: Maybe check for x64 or x86
return _IsProgramInstalled("Microsoft Visual C++ 2010");
}
private static bool _IsVC2015To2022Installed()
{
const string baseKey = @"SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\";
@@ -154,13 +90,6 @@ namespace Vocaluxe
public static bool CheckRequirements()
{
#if WIN
if (!_IsVC2010Installed())
{
CLog.Fatal(
"VC++ 2010 Redistributables are missing. Please install them first.\r\nDownload: https://www.microsoft.com/download/details.aspx?id=26999");
return false;
}
if (!_IsVC2015To2022Installed())
{
CLog.Fatal(
+297 -190
View File
@@ -20,11 +20,11 @@ using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Numerics;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using SlimDX;
using SlimDX.Direct3D9;
using SlimDX.Windows;
using SharpGen.Runtime;
using Vortice.Direct3D9;
using Vocaluxe.Base;
using VocaluxeLib;
using VocaluxeLib.Draw;
@@ -32,12 +32,28 @@ using VocaluxeLib.Log;
namespace Vocaluxe.Lib.Draw
{
class CRenderFormHook : RenderForm, IFormHook
class CRenderFormHook : Form, IFormHook
{
private const int _WmMenuChar = 0x0120;
private const int _MncClose = 1;
public MessageEventHandler OnMessage { private get; set; }
public CRenderFormHook()
{
SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.Opaque, true);
}
protected override void OnPaintBackground(PaintEventArgs e) { }
protected override void WndProc(ref Message m)
{
if (m.Msg == _WmMenuChar)
{
m.Result = new IntPtr(_MncClose << 16);
return;
}
if (OnMessage == null || OnMessage(ref m))
{
base.WndProc(ref m);
@@ -47,15 +63,15 @@ namespace Vocaluxe.Lib.Draw
class CD3DTexture : CTextureBase
{
public readonly Texture D3DTexture;
public readonly IDirect3DTexture9 D3DTexture;
public CD3DTexture(Device device, Size dataSize, int texWidth = 0, int texHeight = 0) : base(dataSize, new Size(texWidth, texHeight))
public CD3DTexture(IDirect3DDevice9 device, Size dataSize, int texWidth = 0, int texHeight = 0) : base(dataSize, new Size(texWidth, texHeight))
{
var noMips = texWidth >= 1280 || texHeight >= 720;
var usage = noMips ? Usage.None : Usage.AutoGenerateMipMap;
var levels = noMips ? 1 : 0;
D3DTexture = device == null ? null : new Texture(device, texWidth, texHeight, levels, usage, Format.A8R8G8B8, Pool.Managed);
D3DTexture = device?.CreateTexture(texWidth, texHeight, levels, usage, Format.A8R8G8B8, Pool.Managed);
}
public override bool IsLoaded
@@ -80,18 +96,21 @@ namespace Vocaluxe.Lib.Draw
class CDirect3D : CDrawBaseWindows<CD3DTexture>, IDraw
{
private readonly Direct3D _D3D;
private readonly Device _Device;
private readonly PresentParameters _PresentParameters;
private const int _D3DErrDeviceLost = unchecked((int)0x88760868);
private const int _D3DErrDeviceNotReset = unchecked((int)0x88760869);
private VertexBuffer _VertexBuffer;
private IndexBuffer _IndexBuffer;
private readonly IDirect3D9 _D3D;
private readonly IDirect3DDevice9 _Device;
private PresentParameters _PresentParameters;
private IDirect3DVertexBuffer9 _VertexBuffer;
private IDirect3DIndexBuffer9 _IndexBuffer;
private CTextureRef _BlankTexture;
private readonly Queue<STexturedColoredVertex> _Vertices = new Queue<STexturedColoredVertex>();
private readonly Queue<Texture> _VerticesTextures = new Queue<Texture>();
private readonly Queue<Matrix> _VerticesRotationMatrices = new Queue<Matrix>();
private readonly Queue<IDirect3DTexture9> _VerticesTextures = new Queue<IDirect3DTexture9>();
private readonly Queue<Matrix4x4> _VerticesRotationMatrices = new Queue<Matrix4x4>();
/// <summary>
/// Creates a new Instance of the CDirect3D Class
@@ -102,11 +121,17 @@ namespace Vocaluxe.Lib.Draw
try
{
_D3D = new Direct3D();
_D3D = D3D9.Direct3DCreate9();
}
catch (Direct3DX9NotFoundException e)
catch (Exception e)
{
CLog.Error(e, "No DirectX runtimes were found, please download and install them from http://www.microsoft.com/download/en/details.aspx?id=8109");
CLog.Error(e, "Direct3D 9 could not be initialized, please check if your graphic card drivers are up to date.");
}
if (_D3D == null)
{
CLog.Fatal("Direct3D 9 is not available on this system.");
return;
}
_Form.KeyDown += _OnKeyDown;
@@ -121,15 +146,22 @@ namespace Vocaluxe.Lib.Draw
_Form.MouseLeave += _OnMouseLeave;
_Form.MouseEnter += _OnMouseEnter;
const int adapter = 0;
var displayFormat = _D3D.GetAdapterDisplayMode(adapter).Format;
var depthFormat = _D3D.CheckDepthStencilMatch(adapter, DeviceType.Hardware, displayFormat, displayFormat, Format.D24X8).Success ? Format.D24X8 : Format.D16;
_PresentParameters = new PresentParameters
{
Windowed = true,
SwapEffect = SwapEffect.Discard,
BackBufferHeight = CConfig.Config.Graphics.ScreenH,
BackBufferWidth = CConfig.Config.Graphics.ScreenW * CConfig.Config.Graphics.NumScreens,
BackBufferFormat = _D3D.Adapters.DefaultAdapter.CurrentDisplayMode.Format,
Multisample = MultisampleType.None,
MultisampleQuality = 0
BackBufferFormat = displayFormat,
EnableAutoDepthStencil = true,
AutoDepthStencilFormat = depthFormat,
MultiSampleType = MultisampleType.None,
MultiSampleQuality = 0
};
//Apply antialiasing and check if antialiasing mode is supported
@@ -157,24 +189,22 @@ namespace Vocaluxe.Lib.Draw
break;
}
if (
!_D3D.CheckDeviceMultisampleType(_D3D.Adapters.DefaultAdapter.Adapter, DeviceType.Hardware, _D3D.Adapters.DefaultAdapter.CurrentDisplayMode.Format, false, msType,
out quality))
if (_D3D.CheckDeviceMultiSampleType(adapter, DeviceType.Hardware, displayFormat, false, msType, out quality).Failure)
{
CLog.Error("[Direct3D] This AAMode is not supported by this device or driver, fallback to no AA");
msType = MultisampleType.None;
quality = 1;
}
_PresentParameters.Multisample = msType;
_PresentParameters.MultisampleQuality = quality - 1;
_PresentParameters.MultiSampleType = msType;
_PresentParameters.MultiSampleQuality = quality - 1;
#endregion Antialiasing
//Apply the VSync configuration
_PresentParameters.PresentationInterval = CConfig.Config.Graphics.VSync == EOffOn.TR_CONFIG_ON ? PresentInterval.Default : PresentInterval.Immediate;
//GMA 950 graphics devices can only process vertices in software mode
var caps = _D3D.GetDeviceCaps(_D3D.Adapters.DefaultAdapter.Adapter, DeviceType.Hardware);
var caps = _D3D.GetDeviceCaps(adapter, DeviceType.Hardware);
var flags = (caps.DeviceCaps & DeviceCaps.HWTransformAndLight) != 0 ? CreateFlags.HardwareVertexProcessing : CreateFlags.SoftwareVertexProcessing;
//Check if Pow2 textures are needed
@@ -185,7 +215,7 @@ namespace Vocaluxe.Lib.Draw
try
{
_Device = new Device(_D3D, _D3D.Adapters.DefaultAdapter.Adapter, DeviceType.Hardware, _Form.Handle, flags, _PresentParameters);
_Device = _D3D.CreateDevice(adapter, DeviceType.Hardware, _Form.Handle, flags, _PresentParameters);
}
catch (Exception e)
{
@@ -193,10 +223,9 @@ namespace Vocaluxe.Lib.Draw
}
finally
{
if (_Device == null || _Device.Disposed)
if (_Device == null)
{
CLog.Fatal(
"Something went wrong during device creating, please check if your DirectX redistributables and grafic card drivers are up to date. You can download the DirectX runtimes at http://www.microsoft.com/download/en/details.aspx?id=8109");
CLog.Fatal("Something went wrong during device creating, please check if your grafic card drivers are up to date.");
}
}
}
@@ -235,9 +264,6 @@ namespace Vocaluxe.Lib.Draw
_ClearScreen();
//To set new PresentParameters the device has to be resetted
_Reset();
//All configurations got flushed due to Reset(), so apply them again
_InitDevice();
_Device.Viewport = new Viewport(_X, _Y, _W, _H);
}
//Store size so it can get restored after the window gets minimized
@@ -271,7 +297,7 @@ namespace Vocaluxe.Lib.Draw
return false;
}
if (_Device.Disposed)
if (_Device == null)
{
return false;
}
@@ -294,88 +320,36 @@ namespace Vocaluxe.Lib.Draw
{
_AdjustNewBorders();
_VertexBuffer = new VertexBuffer(_Device, CSettings.VertexBufferElements * 4 * Marshal.SizeOf(typeof(STexturedColoredVertex)), Usage.WriteOnly | Usage.Dynamic,
var vertexSize = Marshal.SizeOf(typeof(STexturedColoredVertex));
_VertexBuffer = _Device.CreateVertexBuffer(CSettings.VertexBufferElements * 4 * vertexSize, Usage.WriteOnly | Usage.Dynamic,
VertexFormat.Position | VertexFormat.Texture1 | VertexFormat.Diffuse, Pool.Default);
if (_Device.SetStreamSource(0, _VertexBuffer, 0, Marshal.SizeOf(typeof(STexturedColoredVertex))).IsFailure)
{
CLog.Error("Failed to set stream source");
}
_Device.SetStreamSource(0, _VertexBuffer, 0, vertexSize);
_Device.VertexDeclaration = STexturedColoredVertex.GetDeclaration(_Device);
if (_Device.SetRenderState(RenderState.CullMode, Cull.None).IsFailure)
_Device.SetRenderState(RenderState.CullMode, (int)Cull.None);
_Device.SetRenderState(RenderState.ZEnable, (int)ZBufferType.UseZBuffer);
_Device.SetRenderState(RenderState.ZFunc, (int)Compare.LessEqual);
_Device.SetRenderState(RenderState.ZWriteEnable, true);
_Device.SetRenderState(RenderState.AlphaBlendEnable, true);
_Device.SetRenderState(RenderState.Lighting, false);
_Device.SetRenderState(RenderState.DestinationBlend, (int)Blend.InverseSourceAlpha);
_Device.SetRenderState(RenderState.SourceBlend, (int)Blend.SourceAlpha);
if (_PresentParameters.MultiSampleType != MultisampleType.None)
{
CLog.Error("Failed to set cull mode");
_Device.SetRenderState(RenderState.MultisampleAntialias, true);
}
if (_Device.SetRenderState(RenderState.AlphaBlendEnable, true).IsFailure)
{
CLog.Error("Failed to enable alpha blending");
}
_Device.SetSamplerState(0, SamplerState.MinFilter, (int)TextureFilter.Linear);
_Device.SetSamplerState(0, SamplerState.MagFilter, (int)TextureFilter.Linear);
_Device.SetSamplerState(0, SamplerState.MipFilter, (int)TextureFilter.Linear);
_Device.SetSamplerState(0, SamplerState.AddressU, (int)TextureAddress.Clamp);
_Device.SetSamplerState(0, SamplerState.AddressV, (int)TextureAddress.Clamp);
if (_Device.SetRenderState(RenderState.Lighting, false).IsFailure)
{
CLog.Error("Failed to disable lighting");
}
if (_Device.SetRenderState(RenderState.DestinationBlend, Blend.InverseSourceAlpha).IsFailure)
{
CLog.Error("Failed to set destination blend");
}
if (_Device.SetRenderState(RenderState.SourceBlend, Blend.SourceAlpha).IsFailure)
{
CLog.Error("Failed to set source blend");
}
if (_PresentParameters.Multisample != MultisampleType.None)
{
if (_Device.SetRenderState(RenderState.MultisampleAntialias, true).IsFailure)
{
CLog.Error("Failed to set antialiasing");
}
}
if (_Device.SetSamplerState(0, SamplerState.MinFilter, TextureFilter.Linear).IsFailure)
{
CLog.Error("Failed to set min filter");
}
if (_Device.SetSamplerState(0, SamplerState.MagFilter, TextureFilter.Linear).IsFailure)
{
CLog.Error("Failed to set mag filter");
}
if (_Device.SetSamplerState(0, SamplerState.MipFilter, TextureFilter.Linear).IsFailure)
{
CLog.Error("Failed to set mip filter");
}
if (_Device.SetSamplerState(0, SamplerState.AddressU, TextureAddress.Clamp).IsFailure)
{
CLog.Error("Failed to set clamping on u");
}
if (_Device.SetSamplerState(0, SamplerState.AddressV, TextureAddress.Clamp).IsFailure)
{
CLog.Error("Failed to set claming on v");
}
if (_Device.SetTextureStageState(0, TextureStage.AlphaArg1, TextureArgument.Texture).IsFailure)
{
CLog.Error("Failed to set alpha argument 1");
}
if (_Device.SetTextureStageState(0, TextureStage.AlphaArg2, TextureArgument.Diffuse).IsFailure)
{
CLog.Error("Failed to set alpha argument 2");
}
if (_Device.SetTextureStageState(0, TextureStage.AlphaOperation, TextureOperation.Modulate).IsFailure)
{
CLog.Error("Failed to set alpha operation");
}
_Device.SetTextureStageState(0, TextureStage.AlphaArg1, (int)TextureArgument.Texture);
_Device.SetTextureStageState(0, TextureStage.AlphaArg2, (int)TextureArgument.Diffuse);
_Device.SetTextureStageState(0, TextureStage.AlphaOperation, (int)TextureOperation.Modulate);
var indices = new Int16[6];
indices[0] = 0;
@@ -385,85 +359,123 @@ namespace Vocaluxe.Lib.Draw
indices[4] = 2;
indices[5] = 3;
_IndexBuffer = new IndexBuffer(_Device, 6 * sizeof(Int16), Usage.WriteOnly, Pool.Managed, true);
_IndexBuffer = _Device.CreateIndexBuffer(6 * sizeof(Int16), Usage.WriteOnly, true, Pool.Managed);
var stream = _IndexBuffer.Lock(0, 0, LockFlags.Discard);
stream.WriteRange(indices);
var indexData = _IndexBuffer.Lock<byte>(0, 6 * sizeof(Int16), LockFlags.Discard);
MemoryMarshal.AsBytes(indices.AsSpan()).CopyTo(indexData);
_IndexBuffer.Unlock();
_Device.Indices = _IndexBuffer;
}
protected override void _OnBeforeDraw()
{
if (_Device.BeginScene().IsFailure)
try
{
CLog.Error("Failed to begin scene");
_Device.BeginScene();
}
catch (SharpGenException e)
{
CLog.Error(e, "Failed to begin scene");
}
}
protected override void _OnAfterDraw()
{
_RenderVertexBuffer();
if (_Device.EndScene().IsFailure)
{
CLog.Error("Failed to end scene");
}
try
{
//Now push the frame to the Viewport
_Device.Present();
_Device.EndScene();
}
catch (Direct3D9Exception)
catch (SharpGenException e)
{
CLog.Error(e, "Failed to end scene");
}
//Now push the frame to the Viewport
var result = _Device.Present();
if (result.Failure)
{
//In Direct3D devices can get lost.
//This happens for example when opening the Task Manager in Vista/Windows 7 or if a UAC message is opening
//We need to reset the device to get it to workable state again
//After a reset Init() needs to be called because all data in the Direct3D default pool are lost and need to be recreated
if (_Device.TestCooperativeLevel() == ResultCode.DeviceNotReset)
if (_GetCooperativeLevel() == _D3DErrDeviceNotReset)
{
_Reset();
_InitDevice();
}
else if (result.Code != _D3DErrDeviceLost)
{
CLog.Error("Failed to present the frame: " + result);
}
}
Application.DoEvents();
}
private int _GetCooperativeLevel()
{
try
{
_Device.TestCooperativeLevel();
return 0;
}
catch (SharpGenException e)
{
return e.ResultCode.Code;
}
}
/// <summary>
/// Resets the device, all objects in the Direct3D default pool get flushed and need to be recreated
/// </summary>
private void _Reset()
{
//Dispose all objects in the default pool, those need to be recreated
STexturedColoredVertex.GetDeclaration(_Device).Dispose();
_VertexBuffer.Dispose();
_IndexBuffer.Dispose();
if (_Device.Reset(_PresentParameters).IsFailure)
_DisposeDeviceResources();
try
{
CLog.Error("Failed to reset the device");
_Device.Reset(ref _PresentParameters);
//All configurations got flushed due to Reset(), so apply them again
_InitDevice();
_Device.Viewport = new Viewport { X = _X, Y = _Y, Width = _W, Height = _H, MinZ = 0f, MaxZ = 1f };
}
catch (SharpGenException e)
{
CLog.Error(e, "Failed to reset the device");
_DisposeDeviceResources();
}
}
private void _DisposeDeviceResources()
{
STexturedColoredVertex.DisposeDeclaration();
_VertexBuffer?.Dispose();
_VertexBuffer = null;
_IndexBuffer?.Dispose();
_IndexBuffer = null;
}
protected override void _AdjustNewBorders()
{
const float dx = (float)CSettings.RenderW / 2;
const float dy = (float)CSettings.RenderH / 2;
var translate = Matrix.Translation(new Vector3(-dx, dy, 0));
var projection = Matrix.OrthoOffCenterLH(
var translate = Matrix4x4.CreateTranslation(-dx, dy, 0);
var projection = _CreateOrthoOffCenterLH(
-dx - _BorderLeft, CSettings.RenderW * CConfig.Config.Graphics.NumScreens - dx + _BorderRight,
-dy - _BorderBottom, dy + _BorderTop,
CSettings.ZNear, CSettings.ZFar);
if (_Device.SetTransform(TransformState.Projection, projection).IsFailure)
{
CLog.Error("Failed to set orthogonal matrix");
}
_Device.SetTransform(TransformState.Projection, projection);
_Device.SetTransform(0, translate);
}
if (_Device.SetTransform(TransformState.World, translate).IsFailure)
{
CLog.Error("Failed to set translation matrix");
}
private static Matrix4x4 _CreateOrthoOffCenterLH(float left, float right, float bottom, float top, float zNear, float zFar)
{
return new Matrix4x4(
2f / (right - left), 0f, 0f, 0f,
0f, 2f / (top - bottom), 0f, 0f,
0f, 0f, 1f / (zFar - zNear), 0f,
(left + right) / (left - right), (top + bottom) / (bottom - top), zNear / (zNear - zFar), 1f);
}
/// <summary>
@@ -473,11 +485,9 @@ namespace Vocaluxe.Lib.Draw
public override void Close()
{
base.Close();
STexturedColoredVertex.DisposeDeclaration();
_VertexBuffer.Dispose();
_IndexBuffer.Dispose();
_Device.Dispose();
_D3D.Dispose();
_DisposeDeviceResources();
_Device?.Dispose();
_D3D?.Dispose();
}
/// <summary>
@@ -540,7 +550,7 @@ namespace Vocaluxe.Lib.Draw
/// <param name="vertices">A TexturedColoredVertex array containg 4 vertices</param>
/// <param name="tex">The texture the vertex should be textured with</param>
/// <param name="rotation">The vertices' rotation</param>
private void _AddToVertexBuffer(STexturedColoredVertex[] vertices, Texture tex, Matrix rotation)
private void _AddToVertexBuffer(STexturedColoredVertex[] vertices, IDirect3DTexture9 tex, Matrix4x4 rotation)
{
//The vertexbuffer is full, so we need to flush it before we can continue
if (_Vertices.Count >= CSettings.VertexBufferElements)
@@ -566,30 +576,31 @@ namespace Vocaluxe.Lib.Draw
return;
}
//The vertex buffer locks are slow actions, its better to lock once per frame and write all vertices to the buffer at once
var stream = _VertexBuffer.Lock(0, _Vertices.Count * Marshal.SizeOf(typeof(STexturedColoredVertex)), LockFlags.Discard);
stream.WriteRange(_Vertices.ToArray());
_VertexBuffer.Unlock();
stream.Dispose();
for (var i = 0; i < _Vertices.Count; i += 4)
if (_VertexBuffer != null)
{
//Apply rotation
if (_Device.SetTransform(TransformState.World, _VerticesRotationMatrices.Dequeue()).IsFailure)
try
{
CLog.Error("Failed to set world transformation");
}
//The vertex buffer locks are slow actions, its better to lock once per frame and write all vertices to the buffer at once
var vertexData = MemoryMarshal.AsBytes(_Vertices.ToArray().AsSpan());
var bufferData = _VertexBuffer.Lock<byte>(0, vertexData.Length, LockFlags.Discard);
vertexData.CopyTo(bufferData);
_VertexBuffer.Unlock();
//Apply texture
if (_Device.SetTexture(0, _VerticesTextures.Dequeue()).IsFailure)
{
CLog.Error("Failed to set texture");
}
for (var i = 0; i < _Vertices.Count; i += 4)
{
//Apply rotation
_Device.SetTransform(0, _VerticesRotationMatrices.Dequeue());
//Draw 2 triangles from vertexbuffer
if (_Device.DrawIndexedPrimitives(PrimitiveType.TriangleList, i, 0, 4, 0, 2).IsFailure)
//Apply texture
_Device.SetTexture(0, _VerticesTextures.Dequeue());
//Draw 2 triangles from vertexbuffer
_Device.DrawIndexedPrimitive(PrimitiveType.TriangleList, i, 0, 4, 0, 2);
}
}
catch (SharpGenException e)
{
CLog.Error("Failed to draw quad");
CLog.Error(e, "Failed to render the vertex buffer");
}
}
@@ -605,9 +616,94 @@ namespace Vocaluxe.Lib.Draw
/// </summary>
protected override void _ClearScreen()
{
if (_Device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.Black, 1.0f, 0).IsFailure)
try
{
CLog.Error("Failed to clear the backbuffer");
_Device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, new Vortice.Mathematics.Color(0, 0, 0, 255), 1.0f, 0);
}
catch (SharpGenException e)
{
CLog.Error(e, "Failed to clear the backbuffer");
}
}
private int[] _ReadBackBuffer(out int width, out int height)
{
width = 0;
height = 0;
try
{
using (var backBuffer = _Device.GetBackBuffer(0, 0))
{
var desc = backBuffer.Description;
if (desc.Format != Format.X8R8G8B8 && desc.Format != Format.A8R8G8B8)
{
CLog.Error("Reading the backbuffer is not supported for format " + desc.Format);
return null;
}
width = desc.Width;
height = desc.Height;
var rect = new Rect(0, 0, width, height);
using (var renderTarget = _Device.CreateRenderTarget(width, height, desc.Format, MultisampleType.None, 0, false))
using (var sysMemSurface = _Device.CreateOffscreenPlainSurface(width, height, desc.Format, Pool.SystemMemory))
{
_Device.StretchRect(backBuffer, rect, renderTarget, rect, TextureFilter.None);
_Device.GetRenderTargetData(renderTarget, sysMemSurface);
var pixels = new int[width * height];
var locked = sysMemSurface.LockRect(LockFlags.ReadOnly);
try
{
for (var y = 0; y < height; y++)
{
Marshal.Copy(IntPtr.Add(locked.DataPointer, y * locked.Pitch), pixels, y * width, width);
}
}
finally
{
sysMemSurface.UnlockRect();
}
for (var i = 0; i < pixels.Length; i++)
{
pixels[i] |= unchecked((int)0xFF000000);
}
return pixels;
}
}
}
catch (SharpGenException e)
{
CLog.Error(e, "Failed to read the backbuffer");
return null;
}
}
private void _CopyBackBufferToTexture(CD3DTexture texture)
{
int bufferWidth, bufferHeight;
var pixels = _ReadBackBuffer(out bufferWidth, out bufferHeight);
if (pixels == null)
{
return;
}
var width = Math.Min(Math.Min(_W, bufferWidth), texture.Size.Width);
var height = Math.Min(Math.Min(_H, bufferHeight), texture.Size.Height);
var locked = texture.D3DTexture.LockRect(0, LockFlags.Discard);
try
{
for (var y = 0; y < height; y++)
{
Marshal.Copy(pixels, y * bufferWidth, IntPtr.Add(locked.DataPointer, y * locked.Pitch), width);
}
}
finally
{
texture.D3DTexture.UnlockRect(0);
}
}
@@ -618,10 +714,7 @@ namespace Vocaluxe.Lib.Draw
public CTextureRef CopyScreen()
{
var tex = _CreateTexture(new Size(_W, _H));
var backbufferSurface = _Device.GetBackBuffer(0, 0);
var textureSurface = tex.D3DTexture.GetSurfaceLevel(0);
Surface.FromSurface(textureSurface, backbufferSurface, Filter.Default, 0, new Rectangle(0, 0, _W, _H), new Rectangle(0, 0, _W, _H));
backbufferSurface.Dispose();
_CopyBackBufferToTexture(tex);
return _GetTextureReference(_W, _H, tex);
}
@@ -640,10 +733,7 @@ namespace Vocaluxe.Lib.Draw
}
else
{
var backbufferSurface = _Device.GetBackBuffer(0, 0);
var textureSurface = texture.D3DTexture.GetSurfaceLevel(0);
Surface.FromSurface(textureSurface, backbufferSurface, Filter.Default, 0);
backbufferSurface.Dispose();
_CopyBackBufferToTexture(texture);
}
}
@@ -654,12 +744,29 @@ namespace Vocaluxe.Lib.Draw
{
var file = CHelper.GetUniqueFileName(Path.Combine(CSettings.DataFolder, CSettings.FolderNameScreenshots), "Screenshot.png");
//create a surface of the frame
using (var surface = _Device.GetBackBuffer(0, 0))
int width, height;
var pixels = _ReadBackBuffer(out width, out height);
if (pixels == null)
{
var screen = new Bitmap(Surface.ToStream(surface, ImageFileFormat.Png));
return;
}
using (var screen = new Bitmap(width, height, PixelFormat.Format32bppArgb))
{
var bmpData = screen.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
try
{
for (var y = 0; y < height; y++)
{
Marshal.Copy(pixels, y * width, IntPtr.Add(bmpData.Scan0, y * bmpData.Stride), width);
}
}
finally
{
screen.UnlockBits(bmpData);
}
screen.Save(file, ImageFormat.Png);
screen.Dispose();
}
}
@@ -697,11 +804,11 @@ namespace Vocaluxe.Lib.Draw
protected override void _WriteDataToTexture(CD3DTexture texture, byte[] data)
{
var rect = texture.D3DTexture.LockRectangle(0, LockFlags.Discard);
var rect = texture.D3DTexture.LockRect(0, LockFlags.Discard);
try
{
var rowWidth = 4 * texture.DataSize.Width;
var dst = rect.Data.DataPointer;
var dst = rect.DataPointer;
if (rowWidth == rect.Pitch)
Marshal.Copy(data, 0, dst, data.Length);
else
@@ -711,21 +818,21 @@ namespace Vocaluxe.Lib.Draw
Marshal.Copy(data, y * rowWidth, IntPtr.Add(dst, y * rect.Pitch), rowWidth);
}
}
finally { texture.D3DTexture.UnlockRectangle(0); }
finally { texture.D3DTexture.UnlockRect(0); }
}
private static Matrix _CalculateRotationMatrix(float rot, float rx1, float rx2, float ry1, float ry2)
private static Matrix4x4 _CalculateRotationMatrix(float rot, float rx1, float rx2, float ry1, float ry2)
{
var originTranslation = Matrix.Translation(new Vector3(-(float)CSettings.RenderW / 2, (float)CSettings.RenderH / 2, 0));
var originTranslation = Matrix4x4.CreateTranslation(-(float)CSettings.RenderW / 2, (float)CSettings.RenderH / 2, 0);
if (Math.Abs(rot) > float.Epsilon)
{
var rotation = rot * (float)Math.PI / 180;
var centerX = (rx1 + rx2) / 2f;
var centerY = -(ry1 + ry2) / 2f;
var translationA = Matrix.Translation(-centerX, -centerY, 0);
var rotationMat = Matrix.RotationZ(-rotation);
var translationB = Matrix.Translation(centerX, centerY, 0);
var translationA = Matrix4x4.CreateTranslation(-centerX, -centerY, 0);
var rotationMat = Matrix4x4.CreateRotationZ(-rotation);
var translationB = Matrix4x4.CreateTranslation(centerX, centerY, 0);
//Multiplicate the matrices to get the real world matrix,
//First shift the texture into the center
@@ -740,7 +847,7 @@ namespace Vocaluxe.Lib.Draw
private struct STexturedColoredVertex
{
private static VertexDeclaration _Declaration;
private static IDirect3DVertexDeclaration9 _Declaration;
private static readonly VertexElement[] _Elements =
{
new VertexElement(0, 0, DeclarationType.Float3, DeclarationMethod.Default, DeclarationUsage.Position, 0),
@@ -762,11 +869,11 @@ namespace Vocaluxe.Lib.Draw
_Color = color;
}
public static VertexDeclaration GetDeclaration(Device device)
public static IDirect3DVertexDeclaration9 GetDeclaration(IDirect3DDevice9 device)
{
if (_Declaration == null || _Declaration.Disposed)
if (_Declaration == null)
{
_Declaration = new VertexDeclaration(device, _Elements);
_Declaration = device.CreateVertexDeclaration(_Elements);
}
return _Declaration;
@@ -774,7 +881,7 @@ namespace Vocaluxe.Lib.Draw
public static void DisposeDeclaration()
{
if (_Declaration != null && !_Declaration.Disposed)
if (_Declaration != null)
{
_Declaration.Dispose();
_Declaration = null;
@@ -1,133 +0,0 @@
#region license
// This file is part of Vocaluxe.
//
// Vocaluxe is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Vocaluxe is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Vocaluxe. If not, see <http://www.gnu.org/licenses/>.
#endregion
using System.Collections.Generic;
using System.Linq;
using SlimDX.DirectSound;
namespace Vocaluxe.Lib.Sound.Record.DirectSound
{
class CDirectSoundRecord : CRecordBase, IRecord
{
private bool _Initialized;
private List<CSoundCardSource> _Sources;
public override bool Init()
{
if (!base.Init())
{
return false;
}
_Sources = new List<CSoundCardSource>();
var devices = DirectSoundCapture.GetDevices();
foreach (var dev in devices)
{
using (var ds = new DirectSoundCapture(dev.DriverGuid))
{
var device = new CRecordDevice(_Devices.Count, dev.Description, dev.DriverGuid.ToString(), ds.Capabilities.Channels);
_Devices.Add(device);
}
}
_Initialized = true;
return true;
}
public override void Close()
{
Stop();
_Initialized = false;
base.Close();
}
public bool Start()
{
if (!_Initialized)
{
return false;
}
foreach (var buffer in _Buffer)
{
buffer.Reset();
}
foreach (var device in _Devices)
{
var usingDevice = false;
for (var ch = 0; ch < device.Channels; ++ch)
{
if (device.PlayerChannel[ch] > 0)
{
usingDevice = true;
}
}
if (usingDevice)
{
var source = new CSoundCardSource(device.Driver, (short)device.Channels) { SampleRateKhz = 44.1 };
source.SampleDataReady += _OnDataReady;
source.Start();
_Sources.Add(source);
}
}
return true;
}
public bool Stop()
{
if (!_Initialized)
{
return false;
}
foreach (var source in _Sources)
{
source.Stop();
source.Dispose();
}
_Sources.Clear();
return true;
}
private void _OnDataReady(object sender, CSampleDataEventArgs e)
{
if (!_Initialized)
{
return;
}
var dev = _Devices.FirstOrDefault(device => device.Driver == e.Guid);
if (dev == null)
{
return;
}
_HandleData(dev, e.Data);
}
}
}
@@ -1,33 +0,0 @@
#region license
// This file is part of Vocaluxe.
//
// Vocaluxe is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Vocaluxe is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Vocaluxe. If not, see <http://www.gnu.org/licenses/>.
#endregion
using System;
namespace Vocaluxe.Lib.Sound.Record.DirectSound
{
public class CSampleDataEventArgs : EventArgs
{
public readonly byte[] Data;
public readonly string Guid;
public CSampleDataEventArgs(byte[] data, string guid)
{
Data = data;
Guid = guid;
}
}
}
@@ -1,202 +0,0 @@
#region license
// This file is part of Vocaluxe.
//
// Vocaluxe is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Vocaluxe is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Vocaluxe. If not, see <http://www.gnu.org/licenses/>.
#endregion
using System;
using System.Collections.Generic;
using System.Threading;
using SlimDX.DirectSound;
using SlimDX.Multimedia;
namespace Vocaluxe.Lib.Sound.Record.DirectSound
{
public class CSoundCardSource : IDisposable
{
private volatile bool _Running;
private readonly int _BufferSize;
private CaptureBuffer _CaptureBuffer;
private CaptureBufferDescription _BufferDescription;
private DirectSoundCapture _CaptureDevice;
private readonly WaveFormat _WaveFormat;
private Thread _CaptureThread;
private List<NotificationPosition> _Notifications;
private int _BufferPortionCount;
private int _BufferPortionSize;
private WaitHandle[] _WaitHandles;
private double _SampleRate;
private readonly string _Guid;
private readonly short _Channels;
public CSoundCardSource(string guid, short channels)
{
_Guid = guid;
_Channels = channels;
_WaveFormat = new WaveFormat();
SampleRateKhz = 44.1;
_BufferSize = 2048;
}
public event EventHandler<CSampleDataEventArgs> SampleDataReady = delegate { };
public double SampleRateKhz
{
get { return _SampleRate; }
set
{
_SampleRate = value;
if (_Running)
{
Restart();
}
}
}
public void Start()
{
if (_Running)
{
throw new InvalidOperationException();
}
if (_CaptureDevice == null)
{
_CaptureDevice = new DirectSoundCapture(new Guid(_Guid));
}
_WaveFormat.FormatTag = WaveFormatTag.Pcm; // Change to WaveFormatTag.IeeeFloat for float
_WaveFormat.BitsPerSample = 16; // Set this to 32 for float
_WaveFormat.BlockAlignment = (short)(_Channels * (_WaveFormat.BitsPerSample / 8));
_WaveFormat.Channels = _Channels;
_WaveFormat.SamplesPerSecond = (int)(SampleRateKhz * 1000D);
_WaveFormat.AverageBytesPerSecond =
_WaveFormat.SamplesPerSecond *
_WaveFormat.BlockAlignment;
_BufferPortionCount = 2;
_BufferDescription.BufferBytes = _BufferSize * sizeof(short) * _BufferPortionCount * _Channels;
_BufferDescription.Format = _WaveFormat;
_BufferDescription.WaveMapped = false;
_CaptureBuffer = new CaptureBuffer(_CaptureDevice, _BufferDescription);
_BufferPortionSize = _CaptureBuffer.SizeInBytes / _BufferPortionCount;
_Notifications = new List<NotificationPosition>();
for (var i = 0; i < _BufferPortionCount; i++)
{
var notification = new NotificationPosition { Offset = _BufferPortionCount - 1 + _BufferPortionSize * i, Event = new AutoResetEvent(false) };
_Notifications.Add(notification);
}
_CaptureBuffer.SetNotificationPositions(_Notifications.ToArray());
_WaitHandles = new WaitHandle[_Notifications.Count];
for (var i = 0; i < _Notifications.Count; i++)
{
_WaitHandles[i] = _Notifications[i].Event;
}
_CaptureThread = new Thread(_DoCapture) { Name = "DirectSoundCapture", IsBackground = true };
_Running = true;
_CaptureThread.Start();
}
public void Stop()
{
_Running = false;
if (_CaptureThread != null)
{
_CaptureThread.Join();
_CaptureThread = null;
}
if (_CaptureBuffer != null)
{
_CaptureBuffer.Dispose();
_CaptureBuffer = null;
}
if (_Notifications != null)
{
foreach (var notification in _Notifications)
{
notification.Event.Close();
}
_Notifications.Clear();
_Notifications = null;
}
}
public void Restart()
{
Stop();
Start();
}
private void _DoCapture()
{
var bufferPortionSamples = _BufferPortionSize / sizeof(byte);
// Buffer type must match this.waveFormat.FormatTag and this.waveFormat.BitsPerSample
var bufferPortion = new byte[bufferPortionSamples];
_CaptureBuffer.Start(true);
while (_Running)
{
var bufferPortionIndex = WaitHandle.WaitAny(_WaitHandles);
_CaptureBuffer.Read(
bufferPortion,
0,
bufferPortionSamples,
_BufferPortionSize * Math.Abs((bufferPortionIndex - 1) % _BufferPortionCount));
SampleDataReady(this, new CSampleDataEventArgs(bufferPortion, _Guid));
}
_CaptureBuffer.Stop();
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
// ReSharper disable InconsistentNaming
protected void Dispose(bool disposing)
// ReSharper restore InconsistentNaming
{
if (disposing)
{
Stop();
if (_CaptureDevice != null)
{
_CaptureDevice.Dispose();
_CaptureDevice = null;
}
}
}
}
}
@@ -0,0 +1,198 @@
#region license
// This file is part of Vocaluxe.
//
// Vocaluxe is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Vocaluxe is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Vocaluxe. If not, see <http://www.gnu.org/licenses/>.
#endregion
using System;
using System.Collections.Generic;
using NAudio.CoreAudioApi;
using NAudio.Wave;
using VocaluxeLib.Log;
namespace Vocaluxe.Lib.Sound.Record.NAudio
{
class CNAudioRecord : CRecordBase, IRecord
{
private const int _SampleRate = 44100;
private const int _BitsPerSample = 16;
private const int _BufferMilliseconds = 20;
private bool _Initialized;
private MMDeviceEnumerator _Enumerator;
private readonly List<WasapiCapture> _Captures = new List<WasapiCapture>();
public override bool Init()
{
if (!base.Init())
{
return false;
}
try
{
_Enumerator = new MMDeviceEnumerator();
foreach (var device in _Enumerator.EnumerateAudioEndPoints(DataFlow.Capture, DeviceState.Active))
{
try
{
using (device)
using (var client = device.AudioClient)
{
_Devices.Add(new CRecordDevice(_Devices.Count, device.FriendlyName, device.ID, client.MixFormat.Channels));
}
}
catch (Exception e)
{
CLog.Error(e, "Error initializing NAudio record device:");
}
}
_Initialized = true;
}
catch (Exception e)
{
CLog.Error(e, "Error initializing NAudio (WASAPI) recording:");
Close();
return false;
}
return true;
}
public bool Start()
{
if (!_Initialized)
{
return false;
}
Stop();
foreach (var buffer in _Buffer)
{
buffer.Reset();
}
var success = true;
foreach (var dev in _Devices)
{
var usingDevice = false;
for (var ch = 0; ch < dev.Channels; ++ch)
{
if (dev.PlayerChannel[ch] > 0)
{
usingDevice = true;
}
}
if (!usingDevice)
{
continue;
}
WasapiCapture capture = null;
try
{
using (var mmDevice = _Enumerator.GetDevice(dev.Driver))
{
capture = new WasapiCapture(mmDevice, true, _BufferMilliseconds)
{
WaveFormat = new WaveFormat(_SampleRate, _BitsPerSample, dev.Channels)
};
}
var device = dev;
capture.DataAvailable += (sender, e) => _OnDataAvailable(device, e);
capture.RecordingStopped += (sender, e) => _OnRecordingStopped(device, e);
capture.StartRecording();
_Captures.Add(capture);
}
catch (Exception e)
{
CLog.Error(e, "Error starting NAudio record device " + dev.Name + ":");
capture?.Dispose();
success = false;
}
}
return success;
}
public bool Stop()
{
if (!_Initialized)
{
return false;
}
foreach (var capture in _Captures)
{
try
{
capture.Dispose();
}
catch (Exception e)
{
CLog.Error(e, "Error stopping NAudio record device:");
}
}
_Captures.Clear();
return true;
}
public override void Close()
{
Stop();
_Initialized = false;
if (_Enumerator != null)
{
_Enumerator.Dispose();
_Enumerator = null;
}
base.Close();
}
private static void _OnRecordingStopped(CRecordDevice device, StoppedEventArgs e)
{
if (e.Exception != null)
{
CLog.Error(e.Exception, "NAudio record device " + device.Name + " stopped:");
}
}
private void _OnDataAvailable(CRecordDevice device, WaveInEventArgs e)
{
if (e.BytesRecorded <= 0)
{
return;
}
try
{
var recbuffer = new byte[e.BytesRecorded];
Array.Copy(e.Buffer, recbuffer, e.BytesRecorded);
_HandleData(device, recbuffer);
}
catch (Exception ex)
{
CLog.Error(ex, "Error on NAudio record callback:");
}
}
}
}
+5 -4
View File
@@ -198,7 +198,10 @@
<PackageReference Include="vocaluxe.dependencies.opentk" Version="1.0.1" />
<PackageReference Include="vocaluxe.dependencies.portaudiosharp" Version="1.0.3" />
<PackageReference Include="vocaluxe.dependencies.qrcoder" Version="1.0.1" />
<PackageReference Include="vocaluxe.dependencies.slimdx" Version="1.0.1" />
<PackageReference Include="Vortice.Direct3D9" Version="2.4.2" Condition="'$(Configuration)' != 'ReleaseLinux' AND '$(Configuration)' != 'DebugLinux'" />
<PackageReference Include="NAudio.Wasapi" Version="2.2.1" Condition="'$(Configuration)' != 'ReleaseLinux' AND '$(Configuration)' != 'DebugLinux'" />
<!-- PolySharp is pulled in by SharpGen.Runtime (Vortice) and fails the build with Roslyn < 4.3 (VS 2019); Vocaluxe does not need it -->
<PackageReference Include="PolySharp" Version="1.10.0" ExcludeAssets="all" PrivateAssets="all" Condition="'$(Configuration)' != 'ReleaseLinux' AND '$(Configuration)' != 'DebugLinux'" />
</ItemGroup>
<ItemGroup>
<Compile Include="Base\CBackgroundMusic.cs" />
@@ -280,8 +283,6 @@
<Compile Include="Lib\Input\CControllerFramework.cs" />
<Compile Include="Lib\Sound\Playback\GstreamerSharp\CGstreamerSharpAudio.cs" />
<Compile Include="Lib\Sound\Record\CRecordBase.cs" />
<Compile Include="Lib\Sound\Record\DirectSound\CSampleDataEventArgs.cs" Condition=" ('$(Configuration)' == 'DebugWin' Or '$(Configuration)' == 'ReleaseWin' Or '$(Configuration)' == 'InstallerWin')" />
<Compile Include="Lib\Sound\Record\DirectSound\CSoundCardSource.cs" Condition=" ('$(Configuration)' == 'DebugWin' Or '$(Configuration)' == 'ReleaseWin' Or '$(Configuration)' == 'InstallerWin')" />
<Compile Include="Lib\Sound\Record\PitchTracker\CPitchTrackerTest.cs" />
<Compile Include="Lib\Sound\Record\PitchTracker\CPtAKF.cs" />
<Compile Include="Lib\Sound\Record\PitchTracker\CPtDyWa.cs" />
@@ -317,11 +318,11 @@
<Compile Include="Lib\Input\WiiMote\CWiiMote.cs" />
<Compile Include="Lib\Input\WiiMote\WiiMoteLib.cs" />
<Compile Include="Lib\Playlist\CPlaylistFile.cs" />
<Compile Include="Lib\Sound\Record\DirectSound\CDirectSoundRecord.cs" Condition=" ('$(Configuration)' == 'DebugWin' Or '$(Configuration)' == 'ReleaseWin' Or '$(Configuration)' == 'InstallerWin')" />
<Compile Include="Lib\Sound\Playback\OpenAL\COpenALPlay.cs" />
<Compile Include="Base\CSound.cs" />
<Compile Include="Lib\Sound\Playback\PortAudio\CPortAudioPlay.cs" />
<Compile Include="Lib\Sound\Record\PortAudio\CPortAudioRecord.cs" />
<Compile Include="Lib\Sound\Record\NAudio\CNAudioRecord.cs" Condition=" ('$(Configuration)' == 'DebugWin' Or '$(Configuration)' == 'ReleaseWin' Or '$(Configuration)' == 'InstallerWin')" />
<Compile Include="Lib\Sound\Playback\Decoder\CAudioDecoderFFmpeg.cs" />
<Compile Include="Lib\Sound\Playback\Decoder\IAudioDecoder.cs" />
<Compile Include="Lib\Sound\Playback\IPlayback.cs" />
+2 -2
View File
@@ -189,10 +189,10 @@ namespace VocaluxeLib
public enum ERecordLib
{
PortAudio,
#if WIN
DirectSound,
NAudio
#endif
PortAudio
}
public enum EVideoDecoder