commit
de6045c249
80 files changed
+2121
-1858
No files matched your search
@@ -27,32 +27,32 @@ using System.Timers;
|
||||
|
||||
namespace ServerLib
|
||||
{
|
||||
public delegate void OnServerDiscovered(string IPAddress, string Hostname);
|
||||
public delegate void OnServerDiscovered(string ipAddress, string hostname);
|
||||
|
||||
public class CDiscover
|
||||
{
|
||||
public static readonly string sTimeout = "Timeout";
|
||||
public static readonly string sFinished = "Finished";
|
||||
public const string Timeout = "Timeout";
|
||||
public const string Finished = "Finished";
|
||||
|
||||
private string _Keyword;
|
||||
private string _BroadcastAddress;
|
||||
private int _Port;
|
||||
private readonly string _Keyword;
|
||||
private readonly string _BroadcastAddress;
|
||||
private readonly int _Port;
|
||||
|
||||
private Thread _DiscoverThread;
|
||||
private bool _DiscoverRunning;
|
||||
private OnServerDiscovered _OnDiscovered;
|
||||
|
||||
private System.Timers.Timer _BroadcastTimer;
|
||||
private readonly System.Timers.Timer _BroadcastTimer;
|
||||
|
||||
public CDiscover(int Port, string Keyword, string BroadcastAddress = "255.255.255.255")
|
||||
public CDiscover(int port, string keyword, string broadcastAddress = "255.255.255.255")
|
||||
{
|
||||
_BroadcastAddress = BroadcastAddress;
|
||||
_Port = Port;
|
||||
_Keyword = Keyword;
|
||||
_BroadcastAddress = broadcastAddress;
|
||||
_Port = port;
|
||||
_Keyword = keyword;
|
||||
|
||||
_DiscoverRunning = false;
|
||||
_BroadcastTimer = new System.Timers.Timer();
|
||||
_BroadcastTimer.Elapsed += OnBroadcastEvent;
|
||||
_BroadcastTimer.Elapsed += _OnBroadcastEvent;
|
||||
_BroadcastTimer.Interval = 2500;
|
||||
}
|
||||
|
||||
@@ -67,21 +67,20 @@ namespace ServerLib
|
||||
_DiscoverRunning = false;
|
||||
}
|
||||
|
||||
public void Discover(OnServerDiscovered OnDiscovered, int Timeout = 5000)
|
||||
public void Discover(OnServerDiscovered onDiscovered, int timeout = 5000)
|
||||
{
|
||||
if (_DiscoverRunning)
|
||||
return;
|
||||
|
||||
_DiscoverRunning = true;
|
||||
_DiscoverThread = new Thread(() => _Discover(Timeout));
|
||||
_OnDiscovered = OnDiscovered;
|
||||
_DiscoverThread = new Thread(() => _Discover(timeout)) {Name = "Client discover"};
|
||||
_OnDiscovered = onDiscovered;
|
||||
_DiscoverThread.Start();
|
||||
}
|
||||
|
||||
private void OnBroadcastEvent(object source, ElapsedEventArgs e)
|
||||
private void _OnBroadcastEvent(object source, ElapsedEventArgs e)
|
||||
{
|
||||
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
|
||||
s.EnableBroadcast = true;
|
||||
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp) {EnableBroadcast = true};
|
||||
IPAddress broadcast = IPAddress.Parse(_BroadcastAddress);
|
||||
byte[] sendbuf = Encoding.UTF8.GetBytes(_Keyword);
|
||||
IPEndPoint ep = new IPEndPoint(broadcast, _Port);
|
||||
@@ -90,7 +89,7 @@ namespace ServerLib
|
||||
s.Close();
|
||||
}
|
||||
|
||||
private void _Discover(int Timeout)
|
||||
private void _Discover(int timeout)
|
||||
{
|
||||
UdpClient listener = null;
|
||||
Stopwatch timer = new Stopwatch();
|
||||
@@ -98,27 +97,27 @@ namespace ServerLib
|
||||
List<string> knownServer = new List<string>();
|
||||
bool foundSomething = false;
|
||||
timer.Start();
|
||||
while (_DiscoverRunning && timer.ElapsedMilliseconds < Timeout * 2)
|
||||
while (_DiscoverRunning && timer.ElapsedMilliseconds < timeout * 2)
|
||||
{
|
||||
try
|
||||
{
|
||||
listener = new UdpClient(_Port);
|
||||
IPEndPoint groupEP = new IPEndPoint(IPAddress.Any, _Port);
|
||||
listener.Client.ReceiveTimeout = Timeout;
|
||||
IPEndPoint groupEp = new IPEndPoint(IPAddress.Any, _Port);
|
||||
listener.Client.ReceiveTimeout = timeout;
|
||||
|
||||
byte[] bytes = listener.Receive(ref groupEP);
|
||||
byte[] bytes = listener.Receive(ref groupEp);
|
||||
string message = Encoding.UTF8.GetString(bytes, 0, bytes.Length);
|
||||
|
||||
foundSomething = true;
|
||||
if (!knownServer.Contains(groupEP.Address.ToString()))
|
||||
if (!knownServer.Contains(groupEp.Address.ToString()))
|
||||
{
|
||||
knownServer.Add(groupEP.Address.ToString());
|
||||
knownServer.Add(groupEp.Address.ToString());
|
||||
if (_OnDiscovered != null)
|
||||
{
|
||||
IPHostEntry e = Dns.GetHostEntry(groupEP.Address);
|
||||
IPHostEntry e = Dns.GetHostEntry(groupEp.Address);
|
||||
string hostname = e.HostName;
|
||||
|
||||
_OnDiscovered(groupEP.Address.ToString(), hostname);
|
||||
_OnDiscovered(groupEp.Address.ToString(), hostname);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,10 +131,8 @@ namespace ServerLib
|
||||
}
|
||||
_DiscoverRunning = false;
|
||||
|
||||
if (!foundSomething)
|
||||
_OnDiscovered(sTimeout, String.Empty);
|
||||
else
|
||||
_OnDiscovered(sFinished, String.Empty);
|
||||
if (_OnDiscovered != null)
|
||||
_OnDiscovered(!foundSomething ? Timeout : Finished, String.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -142,14 +142,14 @@ namespace ServerLib
|
||||
smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
|
||||
smb.HttpGetEnabled = true;
|
||||
host.Description.Behaviors.Add(smb);*/
|
||||
_RegisterUrlAndCert(_BaseAddress.Port);
|
||||
_RegisterUrlAndCert(_BaseAddress.Port, false);
|
||||
_Host.Open();
|
||||
}
|
||||
catch (CommunicationException e)
|
||||
{
|
||||
if (e is AddressAccessDeniedException || e is AddressAlreadyInUseException)
|
||||
{
|
||||
_RegisterUrlAndCert(_BaseAddress.Port);
|
||||
_RegisterUrlAndCert(_BaseAddress.Port, true);
|
||||
try
|
||||
{
|
||||
_Host.Abort();
|
||||
@@ -178,18 +178,18 @@ namespace ServerLib
|
||||
}
|
||||
}
|
||||
|
||||
private void _RegisterUrlAndCert(int port)
|
||||
private void _RegisterUrlAndCert(int port, bool reserve)
|
||||
{
|
||||
#if WIN
|
||||
|
||||
ProcessStartInfo info = new ProcessStartInfo
|
||||
{
|
||||
FileName = "VocaluxeServerConfig.exe",
|
||||
Arguments = port + " " + (_Encrypted ? "true" : "false"),
|
||||
WorkingDirectory = Environment.CurrentDirectory,
|
||||
Arguments = port + " " + (_Encrypted ? "true" : "false") + (reserve ? " reserve" : ""),
|
||||
UseShellExecute = true,
|
||||
CreateNoWindow = true,
|
||||
WindowStyle = ProcessWindowStyle.Hidden,
|
||||
Verb = "runas"
|
||||
};
|
||||
Process p = Process.Start(info);
|
||||
p.WaitForExit();
|
||||
|
||||
@@ -28,32 +28,27 @@ namespace ServerLib
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/sendKeyEvent?key={key}")]
|
||||
|
||||
void SendKeyEvent(string key);
|
||||
|
||||
#region profile
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/getOwnProfileId")]
|
||||
|
||||
int GetOwnProfileId();
|
||||
|
||||
[OperationContract, WebInvoke(Method = "POST",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/sendProfile")]
|
||||
|
||||
void SendProfile(SProfileData profile);
|
||||
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/getProfile?profileId={profileId}")]
|
||||
|
||||
SProfileData GetProfile(int profileId);
|
||||
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/getProfileList")]
|
||||
|
||||
SProfileData[] GetProfileList();
|
||||
#endregion
|
||||
|
||||
@@ -62,7 +57,6 @@ namespace ServerLib
|
||||
RequestFormat = WebMessageFormat.Json,
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/sendPhoto")]
|
||||
|
||||
void SendPhoto(SPhotoData photo);
|
||||
#endregion
|
||||
|
||||
@@ -70,55 +64,46 @@ namespace ServerLib
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/login?username={username}&password={password}")]
|
||||
|
||||
Guid Login(string username, string password);
|
||||
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "")]
|
||||
|
||||
Stream Index();
|
||||
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/js/{filename}")]
|
||||
|
||||
Stream GetJsFile(String filename);
|
||||
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/css/{filename}")]
|
||||
|
||||
Stream GetCssFile(String filename);
|
||||
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/css/images/{filename}")]
|
||||
|
||||
Stream GetCssImageFile(String filename);
|
||||
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/img/{filename}")]
|
||||
|
||||
Stream GetImgFile(String filename);
|
||||
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/locales/{filename}")]
|
||||
|
||||
Stream GetLocaleFile(String filename);
|
||||
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/delayedImage?id={id}")]
|
||||
|
||||
CBase64Image GetDelayedImage(String id);
|
||||
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/isServerOnline")]
|
||||
|
||||
bool IsServerOnline();
|
||||
#endregion
|
||||
|
||||
@@ -126,19 +111,16 @@ namespace ServerLib
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/getSong?songId={songId}")]
|
||||
|
||||
SSongInfo GetSong(int songId);
|
||||
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/getCurrentSongId")]
|
||||
|
||||
int GetCurrentSongId();
|
||||
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/getAllSongs")]
|
||||
|
||||
SSongInfo[] GetAllSongs();
|
||||
#endregion
|
||||
|
||||
@@ -146,43 +128,36 @@ namespace ServerLib
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/getPlaylists")]
|
||||
|
||||
SPlaylistInfo[] GetPlaylists();
|
||||
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/getPlaylist?id={playlistId}")]
|
||||
|
||||
SPlaylistInfo GetPlaylist(int playlistId);
|
||||
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/addSongToPlaylist?songId={songId}&playlistId={playlistId}&duplicates={allowDuplicates}")]
|
||||
|
||||
void AddSongToPlaylist(int songId, int playlistId, bool allowDuplicates);
|
||||
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/removeSongFromPlaylist?position={position}&playlistId={playlistId}&songId={songId}")]
|
||||
|
||||
void RemoveSongFromPlaylist(int position, int playlistId, int songId);
|
||||
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/moveSongInPlaylist?newPosition={newPosition}&playlistId={playlistId}&songId={songId}")]
|
||||
|
||||
void MoveSongInPlaylist(int newPosition, int playlistId, int songId);
|
||||
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/playlistContainsSong?songId={songId}&playlistId={playlistId}")]
|
||||
|
||||
bool PlaylistContainsSong(int songId, int playlistId);
|
||||
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/getPlaylistSongs?playlistId={playlistId}")]
|
||||
|
||||
SPlaylistSongInfo[] GetPlaylistSongs(int playlistId);
|
||||
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
@@ -200,19 +175,16 @@ namespace ServerLib
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/getUserRole?profileId={profileId}")]
|
||||
|
||||
int GetUserRole(int profileId);
|
||||
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/setUserRole?profileId={profileId}&userRole={userRole}")]
|
||||
|
||||
void SetUserRole(int profileId, int userRole);
|
||||
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/hasUserRight?right={right}")]
|
||||
|
||||
bool HasUserRight(int right);
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<ScreenOptionsRecord>
|
||||
<ScreenVersion>3</ScreenVersion>
|
||||
<ScreenVersion>4</ScreenVersion>
|
||||
<Background1>
|
||||
<!--<Type>: Background type: None, Color, Texture, Video-->
|
||||
<Type>Video</Type>
|
||||
@@ -216,6 +216,35 @@
|
||||
<!-- <Height>: Reflection Height-->
|
||||
</Text2>
|
||||
<Text3>
|
||||
<!--<X>, <Y>: Text position-->
|
||||
<X>75</X>
|
||||
<Y>347</Y>
|
||||
<!--<Z>: Text position-->
|
||||
<Z>0,00</Z>
|
||||
<!--<H>: Text height-->
|
||||
<H>27</H>
|
||||
<!--<MaxW>: Maximum text width (if exists)-->
|
||||
<!--<Color>: Text color from ColorScheme (high priority)-->
|
||||
<!--or <R>, <G>, <B>, <A> (lower priority)-->
|
||||
<Color>StaticColor</Color>
|
||||
<!--<SColor>: Selected Text color from ColorScheme (high priority)-->
|
||||
<!--or <SR>, <SG>, <SB>, <SA> (lower priority)-->
|
||||
<SColor>TextSColor</SColor>
|
||||
<!--<Align>: Text align horizontal: Left, Center, Right-->
|
||||
<Align>Left</Align>
|
||||
<!--<ResizeAlign>: Text align vertical (on downsizing): Top, Center, Bottom-->
|
||||
<HAlign>Center</HAlign>
|
||||
<!--<Style>: Text style: Normal, Italic, Bold, BoldItalic-->
|
||||
<Style>Bold</Style>
|
||||
<!--<Font>: Text font name-->
|
||||
<Font>Outline</Font>
|
||||
<!--<Text>: Nothing or translation tag-->
|
||||
<Text>TR_SCREENORECORD_MIC_DELAY</Text>
|
||||
<!--<Reflection> If exists:-->
|
||||
<!-- <Space>: Reflection Space-->
|
||||
<!-- <Height>: Reflection Height-->
|
||||
</Text3>
|
||||
<TextChannel1>
|
||||
<!--<X>, <Y>: Text position-->
|
||||
<X>75</X>
|
||||
<Y>227</Y>
|
||||
@@ -243,8 +272,8 @@
|
||||
<!--<Reflection> If exists:-->
|
||||
<!-- <Space>: Reflection Space-->
|
||||
<!-- <Height>: Reflection Height-->
|
||||
</Text3>
|
||||
<Text4>
|
||||
</TextChannel1>
|
||||
<TextChannel2>
|
||||
<!--<X>, <Y>: Text position-->
|
||||
<X>75</X>
|
||||
<Y>287</Y>
|
||||
@@ -272,36 +301,7 @@
|
||||
<!--<Reflection> If exists:-->
|
||||
<!-- <Space>: Reflection Space-->
|
||||
<!-- <Height>: Reflection Height-->
|
||||
</Text4>
|
||||
<Text5>
|
||||
<!--<X>, <Y>: Text position-->
|
||||
<X>75</X>
|
||||
<Y>347</Y>
|
||||
<!--<Z>: Text position-->
|
||||
<Z>0,00</Z>
|
||||
<!--<H>: Text height-->
|
||||
<H>27</H>
|
||||
<!--<MaxW>: Maximum text width (if exists)-->
|
||||
<!--<Color>: Text color from ColorScheme (high priority)-->
|
||||
<!--or <R>, <G>, <B>, <A> (lower priority)-->
|
||||
<Color>StaticColor</Color>
|
||||
<!--<SColor>: Selected Text color from ColorScheme (high priority)-->
|
||||
<!--or <SR>, <SG>, <SB>, <SA> (lower priority)-->
|
||||
<SColor>TextSColor</SColor>
|
||||
<!--<Align>: Text align horizontal: Left, Center, Right-->
|
||||
<Align>Left</Align>
|
||||
<!--<ResizeAlign>: Text align vertical (on downsizing): Top, Center, Bottom-->
|
||||
<HAlign>Center</HAlign>
|
||||
<!--<Style>: Text style: Normal, Italic, Bold, BoldItalic-->
|
||||
<Style>Bold</Style>
|
||||
<!--<Font>: Text font name-->
|
||||
<Font>Outline</Font>
|
||||
<!--<Text>: Nothing or translation tag-->
|
||||
<Text>TR_SCREENORECORD_MIC_DELAY</Text>
|
||||
<!--<Reflection> If exists:-->
|
||||
<!-- <Space>: Reflection Space-->
|
||||
<!-- <Height>: Reflection Height-->
|
||||
</Text5>
|
||||
</TextChannel2>
|
||||
<TextWarning>
|
||||
<!--<X>, <Y>: Text position-->
|
||||
<X>640</X>
|
||||
|
||||
@@ -6,4 +6,7 @@ Version 2:
|
||||
Add:
|
||||
<EqualizerChannel1> and <EqualizerChannel2>.
|
||||
This is a new theme-element. Check ScreenOptionsRecord.xml for style-possibilities.
|
||||
++++++++++
|
||||
++++++++++
|
||||
Version 4:
|
||||
Rename Text 3/4 to TextChannel1/2
|
||||
Rename Text5 to Text3
|
||||
@@ -17,7 +17,6 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using VocaluxeLib;
|
||||
@@ -39,7 +38,7 @@ namespace Vocaluxe.Base
|
||||
|
||||
private static int _Video = -1;
|
||||
private static CTexture _CurrentVideoTexture;
|
||||
private static readonly Stopwatch _FadeTimer = new Stopwatch();
|
||||
private static CFading _VideoFading;
|
||||
private static bool _VideoEnabled;
|
||||
|
||||
private static bool _OwnMusicAdded;
|
||||
@@ -442,12 +441,12 @@ namespace Vocaluxe.Base
|
||||
float vtime;
|
||||
if (CVideo.GetFrame(_Video, ref _CurrentVideoTexture, CSound.GetPosition(_CurrentMusicStream), out vtime))
|
||||
{
|
||||
if (_FadeTimer.ElapsedMilliseconds <= 3000L)
|
||||
_CurrentVideoTexture.Color.A = _FadeTimer.ElapsedMilliseconds / 3000f;
|
||||
else
|
||||
if (_VideoFading != null)
|
||||
{
|
||||
_CurrentVideoTexture.Color.A = 1f;
|
||||
_FadeTimer.Stop();
|
||||
bool finished;
|
||||
_CurrentVideoTexture.Color.A = _VideoFading.GetValue(out finished);
|
||||
if (finished)
|
||||
_VideoFading = null;
|
||||
}
|
||||
return _CurrentVideoTexture;
|
||||
}
|
||||
@@ -469,8 +468,7 @@ namespace Vocaluxe.Base
|
||||
CVideo.Skip(_Video, _CurrentPlaylistElement.Start, _CurrentPlaylistElement.VideoGap);
|
||||
else
|
||||
CVideo.Skip(_Video, 0f, _CurrentPlaylistElement.VideoGap);
|
||||
_FadeTimer.Reset();
|
||||
_FadeTimer.Start();
|
||||
_VideoFading = new CFading(0f, 1f, 3f);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -60,10 +60,10 @@ namespace Vocaluxe.Base
|
||||
public static int ScreenW = 1024;
|
||||
public static int ScreenH = 576;
|
||||
|
||||
public static int BorderLeft = 0;
|
||||
public static int BorderRight = 0;
|
||||
public static int BorderTop = 0;
|
||||
public static int BorderBottom = 0;
|
||||
public static int BorderLeft;
|
||||
public static int BorderRight;
|
||||
public static int BorderTop;
|
||||
public static int BorderBottom;
|
||||
|
||||
public static EAntiAliasingModes AAMode = EAntiAliasingModes.X0;
|
||||
|
||||
|
||||
+11
-37
@@ -24,10 +24,7 @@ namespace Vocaluxe.Base
|
||||
{
|
||||
class CCursor
|
||||
{
|
||||
private readonly Stopwatch _CursorFadingTimer = new Stopwatch();
|
||||
private float _CursorTargetAlpha = 1f;
|
||||
private float _CursorStartAlpha;
|
||||
private float _CursorFadingTime = 0.5f;
|
||||
private CFading _Fading;
|
||||
private CTexture _Cursor;
|
||||
|
||||
private readonly Stopwatch _Movetimer = new Stopwatch();
|
||||
@@ -52,28 +49,19 @@ namespace Vocaluxe.Base
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
if (_Movetimer.IsRunning && _Movetimer.ElapsedMilliseconds / 1000f > CSettings.MouseMoveOffTime)
|
||||
if (_Movetimer.IsRunning && _Movetimer.ElapsedMilliseconds > CSettings.MouseMoveOffTime)
|
||||
{
|
||||
_Movetimer.Stop();
|
||||
_Fade(0f, 0.5f);
|
||||
}
|
||||
|
||||
|
||||
if (_CursorFadingTimer.IsRunning)
|
||||
if (_Fading != null)
|
||||
{
|
||||
float t = _CursorFadingTimer.ElapsedMilliseconds / 1000f;
|
||||
if (t < _CursorFadingTime)
|
||||
{
|
||||
if (_CursorTargetAlpha >= _CursorStartAlpha)
|
||||
_Cursor.Color.A = _CursorStartAlpha + (_CursorTargetAlpha - _CursorStartAlpha) * t / _CursorFadingTime;
|
||||
else
|
||||
_Cursor.Color.A = (_CursorStartAlpha - _CursorTargetAlpha) * (1f - t / _CursorFadingTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
_CursorFadingTimer.Stop();
|
||||
_Cursor.Color.A = _CursorTargetAlpha;
|
||||
}
|
||||
bool finished;
|
||||
_Cursor.Color.A = _Fading.GetValue(out finished);
|
||||
if (finished)
|
||||
_Fading = null;
|
||||
}
|
||||
|
||||
if (Visible && (CSettings.GameState == EGameState.EditTheme || ShowCursor))
|
||||
@@ -85,11 +73,10 @@ namespace Vocaluxe.Base
|
||||
if (Math.Abs(_Cursor.Rect.X - x) > CSettings.MouseMoveDiffMin ||
|
||||
Math.Abs(_Cursor.Rect.Y - y) > CSettings.MouseMoveDiffMin)
|
||||
{
|
||||
if (_CursorTargetAlpha < 0.01)
|
||||
if (!IsActive)
|
||||
_Fade(1f, 0.2f);
|
||||
|
||||
_Movetimer.Reset();
|
||||
_Movetimer.Start();
|
||||
_Movetimer.Restart();
|
||||
CSettings.MouseActive();
|
||||
}
|
||||
|
||||
@@ -130,26 +117,13 @@ namespace Vocaluxe.Base
|
||||
|
||||
public void FadeIn()
|
||||
{
|
||||
_Movetimer.Reset();
|
||||
_Movetimer.Start();
|
||||
_Movetimer.Restart();
|
||||
_Fade(1f, 0.2f);
|
||||
}
|
||||
|
||||
private void _Fade(float targetAlpha, float time)
|
||||
{
|
||||
_CursorFadingTimer.Stop();
|
||||
_CursorFadingTimer.Reset();
|
||||
|
||||
if (targetAlpha >= 0f && targetAlpha <= 1f)
|
||||
_CursorTargetAlpha = targetAlpha;
|
||||
else
|
||||
_CursorTargetAlpha = 1f;
|
||||
|
||||
if (time >= 0f)
|
||||
_CursorFadingTime = time;
|
||||
|
||||
_CursorStartAlpha = _Cursor.Color.A;
|
||||
_CursorFadingTimer.Start();
|
||||
_Fading = new CFading(_Cursor.Color.A, targetAlpha, time);
|
||||
}
|
||||
}
|
||||
}
|
||||
+106
-106
@@ -63,8 +63,16 @@ namespace Vocaluxe.Base
|
||||
_CreditsRessourcesFilePath = Path.Combine(Environment.CurrentDirectory, CSettings.FileCreditsRessourcesDB);
|
||||
|
||||
_InitHighscoreDB();
|
||||
_InitCoverDB();
|
||||
_InitCreditsRessourcesDB();
|
||||
if (!_InitCoverDB())
|
||||
{
|
||||
CLog.LogError("Error initializing Cover-DB", true, true);
|
||||
return;
|
||||
}
|
||||
if (!_InitCreditsRessourcesDB())
|
||||
{
|
||||
CLog.LogError("Error initializing Cover-DB", true, true);
|
||||
return;
|
||||
}
|
||||
GC.Collect();
|
||||
}
|
||||
|
||||
@@ -93,26 +101,6 @@ namespace Vocaluxe.Base
|
||||
return _GetDataBaseSongInfos(songID, out sArtist, out sTitle, out numPlayed, out dateAdded, _HighscoreFilePath);
|
||||
}
|
||||
|
||||
public static void IncreaseSongCounter(SPlayer player)
|
||||
{
|
||||
using (var connection = new SQLiteConnection())
|
||||
{
|
||||
connection.ConnectionString = "Data Source=" + _HighscoreFilePath;
|
||||
|
||||
try
|
||||
{
|
||||
connection.Open();
|
||||
}
|
||||
catch (Exception) {}
|
||||
|
||||
using (var command = new SQLiteCommand(connection))
|
||||
{
|
||||
int dataBaseSongID = _GetDataBaseSongID(player, command);
|
||||
_IncreaseSongCounter(dataBaseSongID, command);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void IncreaseSongCounter(int dataBaseSongID)
|
||||
{
|
||||
using (var connection = new SQLiteConnection())
|
||||
@@ -170,11 +158,27 @@ namespace Vocaluxe.Base
|
||||
return -1;
|
||||
}
|
||||
|
||||
int medley = 0;
|
||||
int duet = 0;
|
||||
int shortSong = 0;
|
||||
switch (player.GameMode)
|
||||
{
|
||||
case EGameMode.TR_GAMEMODE_MEDLEY:
|
||||
medley = 1;
|
||||
break;
|
||||
case EGameMode.TR_GAMEMODE_DUET:
|
||||
duet = 1;
|
||||
break;
|
||||
case EGameMode.TR_GAMEMODE_SHORTSONG:
|
||||
shortSong = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
using (var command = new SQLiteCommand(connection))
|
||||
{
|
||||
int dataBaseSongID = CSongs.GetSong(player.SongID).DataBaseSongID;
|
||||
return _AddScore(CProfiles.GetPlayerName(player.ProfileID), (int)Math.Round(player.Points), player.VoiceNr, player.DateTicks, player.Medley ? 1 : 0,
|
||||
player.Duet ? 1 : 0, player.ShortSong ? 1 : 0, (int)CProfiles.GetDifficulty(player.ProfileID), dataBaseSongID, command);
|
||||
return _AddScore(CProfiles.GetPlayerName(player.ProfileID), (int)Math.Round(player.Points), player.VoiceNr, player.DateTicks, medley,
|
||||
duet, shortSong, (int)CProfiles.GetDifficulty(player.ProfileID), dataBaseSongID, command);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -243,70 +247,74 @@ namespace Vocaluxe.Base
|
||||
return lastInsertID;
|
||||
}
|
||||
|
||||
public static void LoadScore(out List<SScores> scores, SPlayer player)
|
||||
public static List<SDBScoreEntry> LoadScore(int songID, EGameMode gameMode)
|
||||
{
|
||||
var scores = new List<SDBScoreEntry>();
|
||||
using (var connection = new SQLiteConnection())
|
||||
{
|
||||
connection.ConnectionString = "Data Source=" + _HighscoreFilePath;
|
||||
|
||||
scores = new List<SScores>();
|
||||
|
||||
try
|
||||
{
|
||||
connection.Open();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return;
|
||||
return scores;
|
||||
}
|
||||
|
||||
using (var command = new SQLiteCommand(connection))
|
||||
{
|
||||
int medley = 0;
|
||||
if (player.Medley)
|
||||
medley = 1;
|
||||
|
||||
int duet = 0;
|
||||
if (player.Duet)
|
||||
duet = 1;
|
||||
|
||||
int shortSong = 0;
|
||||
if (player.ShortSong)
|
||||
shortSong = 1;
|
||||
|
||||
int dataBaseSongID = _GetDataBaseSongID(player, command);
|
||||
if (dataBaseSongID >= 0)
|
||||
switch (gameMode)
|
||||
{
|
||||
command.CommandText = "SELECT PlayerName, Score, Date, Difficulty, LineNr, id FROM Scores " +
|
||||
"WHERE [SongID] = @SongID AND [Medley] = @Medley AND [Duet] = @Duet AND [ShortSong] = @ShortSong " +
|
||||
"ORDER BY [Score] DESC";
|
||||
command.Parameters.Add("@SongID", DbType.Int32, 0).Value = dataBaseSongID;
|
||||
command.Parameters.Add("@Medley", DbType.Int32, 0).Value = medley;
|
||||
command.Parameters.Add("@Duet", DbType.Int32, 0).Value = duet;
|
||||
command.Parameters.Add("@ShortSong", DbType.Int32, 0).Value = shortSong;
|
||||
case EGameMode.TR_GAMEMODE_MEDLEY:
|
||||
medley = 1;
|
||||
break;
|
||||
case EGameMode.TR_GAMEMODE_DUET:
|
||||
duet = 1;
|
||||
break;
|
||||
case EGameMode.TR_GAMEMODE_SHORTSONG:
|
||||
shortSong = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
SQLiteDataReader reader = command.ExecuteReader();
|
||||
if (reader != null && reader.HasRows)
|
||||
int dataBaseSongID = _GetDataBaseSongID(songID, command);
|
||||
if (dataBaseSongID < 0)
|
||||
return scores;
|
||||
|
||||
command.CommandText = "SELECT PlayerName, Score, Date, Difficulty, LineNr, id FROM Scores " +
|
||||
"WHERE [SongID] = @SongID AND [Medley] = @Medley AND [Duet] = @Duet AND [ShortSong] = @ShortSong " +
|
||||
"ORDER BY [Score] DESC";
|
||||
command.Parameters.Add("@SongID", DbType.Int32, 0).Value = dataBaseSongID;
|
||||
command.Parameters.Add("@Medley", DbType.Int32, 0).Value = medley;
|
||||
command.Parameters.Add("@Duet", DbType.Int32, 0).Value = duet;
|
||||
command.Parameters.Add("@ShortSong", DbType.Int32, 0).Value = shortSong;
|
||||
|
||||
SQLiteDataReader reader = command.ExecuteReader();
|
||||
if (reader != null && reader.HasRows)
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
var score = new SScores
|
||||
{
|
||||
Name = reader.GetString(0),
|
||||
Score = reader.GetInt32(1),
|
||||
Date = new DateTime(reader.GetInt64(2)).ToString("dd/MM/yyyy"),
|
||||
Difficulty = (EGameDifficulty)reader.GetInt32(3),
|
||||
LineNr = reader.GetInt32(4),
|
||||
ID = reader.GetInt32(5)
|
||||
};
|
||||
var score = new SDBScoreEntry
|
||||
{
|
||||
Name = reader.GetString(0),
|
||||
Score = reader.GetInt32(1),
|
||||
Date = new DateTime(reader.GetInt64(2)).ToString("dd/MM/yyyy"),
|
||||
Difficulty = (EGameDifficulty)reader.GetInt32(3),
|
||||
VoiceNr = reader.GetInt32(4),
|
||||
ID = reader.GetInt32(5)
|
||||
};
|
||||
|
||||
scores.Add(score);
|
||||
}
|
||||
reader.Dispose();
|
||||
scores.Add(score);
|
||||
}
|
||||
reader.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
return scores;
|
||||
}
|
||||
|
||||
private static void _IncreaseSongCounter(int dataBaseSongID, SQLiteCommand command)
|
||||
@@ -316,9 +324,9 @@ namespace Vocaluxe.Base
|
||||
command.ExecuteNonQuery();
|
||||
}
|
||||
|
||||
private static int _GetDataBaseSongID(SPlayer player, SQLiteCommand command)
|
||||
private static int _GetDataBaseSongID(int songID, SQLiteCommand command)
|
||||
{
|
||||
CSong song = CSongs.GetSong(player.SongID);
|
||||
CSong song = CSongs.GetSong(songID);
|
||||
|
||||
if (song == null)
|
||||
return -1;
|
||||
@@ -430,21 +438,35 @@ namespace Vocaluxe.Base
|
||||
{
|
||||
if (File.Exists(_HighscoreFilePath))
|
||||
{
|
||||
_CreateOrConvert(oldDBFilePath);
|
||||
_CreateOrConvert(_HighscoreFilePath);
|
||||
_ImportData(oldDBFilePath);
|
||||
|
||||
File.Delete(oldDBFilePath);
|
||||
if (!_CreateOrConvert(oldDBFilePath))
|
||||
{
|
||||
CLog.LogError("Cannot init Highscore DB: Error opening database: " + oldDBFilePath, true, true);
|
||||
return;
|
||||
}
|
||||
if (!_CreateOrConvert(_HighscoreFilePath))
|
||||
{
|
||||
CLog.LogError("Cannot init Highscore DB: Error opening database: " + _HighscoreFilePath, true, true);
|
||||
return;
|
||||
}
|
||||
if (!_ImportData(oldDBFilePath))
|
||||
{
|
||||
CLog.LogError("Cannot init Highscore DB: Error importing data", true, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
File.Copy(oldDBFilePath, _HighscoreFilePath);
|
||||
_CreateOrConvert(_HighscoreFilePath);
|
||||
File.Delete(oldDBFilePath);
|
||||
if (!_CreateOrConvert(_HighscoreFilePath))
|
||||
{
|
||||
CLog.LogError("Cannot init Highscore DB: Error opening database: " + _HighscoreFilePath, true, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
File.Delete(oldDBFilePath);
|
||||
}
|
||||
else
|
||||
_CreateOrConvert(_HighscoreFilePath);
|
||||
else if (!_CreateOrConvert(_HighscoreFilePath))
|
||||
CLog.LogError("Cannot init Highscore DB: Error opening database: " + _HighscoreFilePath, true, true);
|
||||
}
|
||||
|
||||
private static void _CreateHighscoreDB(string filePath)
|
||||
@@ -525,6 +547,7 @@ namespace Vocaluxe.Base
|
||||
/// <returns></returns>
|
||||
private static bool _CreateOrConvert(string filePath)
|
||||
{
|
||||
bool result = true;
|
||||
using (var connection = new SQLiteConnection())
|
||||
{
|
||||
connection.ConnectionString = "Data Source=" + filePath;
|
||||
@@ -565,46 +588,24 @@ namespace Vocaluxe.Base
|
||||
}
|
||||
catch (Exception) {}
|
||||
|
||||
if (reader == null)
|
||||
if (reader == null || reader.FieldCount == 0)
|
||||
{
|
||||
// create new database/tables
|
||||
if (version == 1)
|
||||
{
|
||||
//Check for USDX 1.1 DB
|
||||
_CreateHighscoreDBV1(filePath);
|
||||
_ConvertFrom110(filePath);
|
||||
_UpdateDatabase(1, connection);
|
||||
_UpdateDatabase(2, connection);
|
||||
result &= !_ConvertFrom110(filePath);
|
||||
result &= _UpdateDatabase(1, connection);
|
||||
result &= _UpdateDatabase(2, connection);
|
||||
}
|
||||
else if (version == 0 && scoresTableExists)
|
||||
{
|
||||
//Check for USDX 1.01 or CMD Mod DB
|
||||
_CreateHighscoreDBV1(filePath);
|
||||
_ConvertFrom101(filePath);
|
||||
_UpdateDatabase(1, connection);
|
||||
_UpdateDatabase(2, connection);
|
||||
}
|
||||
else
|
||||
_CreateHighscoreDB(filePath);
|
||||
}
|
||||
else if (reader.FieldCount == 0)
|
||||
{
|
||||
// create new database/tables
|
||||
if (version == 1)
|
||||
{
|
||||
//Check for USDX 1.1 DB
|
||||
_CreateHighscoreDBV1(filePath);
|
||||
_ConvertFrom110(filePath);
|
||||
_UpdateDatabase(1, connection);
|
||||
_UpdateDatabase(2, connection);
|
||||
}
|
||||
else if (version == 0 && scoresTableExists)
|
||||
{
|
||||
//Check for USDX 1.01 or CMD Mod DB
|
||||
_CreateHighscoreDBV1(filePath);
|
||||
_ConvertFrom101(filePath);
|
||||
_UpdateDatabase(1, connection);
|
||||
_UpdateDatabase(2, connection);
|
||||
result &= _ConvertFrom101(filePath);
|
||||
result &= _UpdateDatabase(1, connection);
|
||||
result &= _UpdateDatabase(2, connection);
|
||||
}
|
||||
else
|
||||
_CreateHighscoreDB(filePath);
|
||||
@@ -616,7 +617,7 @@ namespace Vocaluxe.Base
|
||||
if (currentVersion < CSettings.DatabaseHighscoreVersion)
|
||||
{
|
||||
// update database
|
||||
_UpdateDatabase(currentVersion, connection);
|
||||
result &= _UpdateDatabase(currentVersion, connection);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -625,7 +626,7 @@ namespace Vocaluxe.Base
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -972,8 +973,7 @@ namespace Vocaluxe.Base
|
||||
lastDateAdded = dateAdded;
|
||||
}
|
||||
}
|
||||
if (reader != null)
|
||||
reader.Dispose();
|
||||
reader.Dispose();
|
||||
|
||||
foreach (int id in ids)
|
||||
_IncreaseSongCounter(id, command);
|
||||
|
||||
+15
-25
@@ -131,7 +131,7 @@ namespace Vocaluxe.Base
|
||||
|
||||
public static void NextRound()
|
||||
{
|
||||
_SongQueue.NextRound(Players);
|
||||
_SongQueue.StartNextRound(Players);
|
||||
}
|
||||
|
||||
public static bool IsFinished()
|
||||
@@ -149,14 +149,14 @@ namespace Vocaluxe.Base
|
||||
return _SongQueue.GetSong();
|
||||
}
|
||||
|
||||
public static CSong GetSong(int num)
|
||||
public static CSong GetSong(int round)
|
||||
{
|
||||
return _SongQueue.GetSong(num);
|
||||
return _SongQueue.GetSong(round);
|
||||
}
|
||||
|
||||
public static EGameMode GetGameMode(int num)
|
||||
public static EGameMode GetGameMode(int round)
|
||||
{
|
||||
return _SongQueue.GetGameMode(num);
|
||||
return _SongQueue.GetGameMode(round);
|
||||
}
|
||||
|
||||
public static int GetNumSongs()
|
||||
@@ -197,9 +197,7 @@ namespace Vocaluxe.Base
|
||||
Players[i].CurrentLine = -1;
|
||||
Players[i].CurrentNote = -1;
|
||||
Players[i].SongID = -1;
|
||||
Players[i].Medley = false;
|
||||
Players[i].Duet = false;
|
||||
Players[i].ShortSong = false;
|
||||
Players[i].GameMode = EGameMode.TR_GAMEMODE_NORMAL;
|
||||
Players[i].DateTicks = DateTime.Now.Ticks;
|
||||
Players[i].SongFinished = false;
|
||||
}
|
||||
@@ -210,7 +208,7 @@ namespace Vocaluxe.Base
|
||||
|
||||
public static void UpdatePoints(float time)
|
||||
{
|
||||
bool DEBUG_HIT = false;
|
||||
const bool DEBUG_HIT = false;
|
||||
|
||||
CSong song = _SongQueue.GetSong();
|
||||
|
||||
@@ -276,8 +274,6 @@ namespace Vocaluxe.Base
|
||||
{
|
||||
int tone = notes[note].Tone;
|
||||
int tonePlayer = CSound.RecordGetTone(p);
|
||||
if (DEBUG_HIT)
|
||||
tonePlayer = tone;
|
||||
|
||||
while (tonePlayer - tone > 6)
|
||||
tonePlayer -= 12;
|
||||
@@ -364,7 +360,7 @@ namespace Vocaluxe.Base
|
||||
|
||||
public static void ResetToLastLine(int soundStream, int vidStream)
|
||||
{
|
||||
float[] time = GetLastSungLineStart();
|
||||
float[] time = _GetLastSungLineStart();
|
||||
ResetToTime(time[0], time[1], soundStream, vidStream);
|
||||
}
|
||||
|
||||
@@ -413,23 +409,20 @@ namespace Vocaluxe.Base
|
||||
}
|
||||
Players[p].SungLines.RemoveRange(deleteLine, Players[p].SungLines.Count - deleteLine);
|
||||
}
|
||||
//CSong song = GetSong();
|
||||
//for (int i = 0; i < GetSong().Notes.Voices[0].Lines.Length; i++)
|
||||
// CLog.LogError((i + 1) + ". " + song.Notes.Voices[0].Lines[i].NoteCount + " - " + Players[0].SungLines[i].NoteCount);
|
||||
|
||||
CSound.SetPosition(soundStream, time);
|
||||
CVideo.Skip(vidStream, time, GetSong().VideoGap);
|
||||
}
|
||||
|
||||
private static float[] GetLastSungLineStart()
|
||||
private static float[] _GetLastSungLineStart()
|
||||
{
|
||||
return GetNoteTimeBeforeBeat(CurrentBeat);
|
||||
return _GetNoteTimeBeforeBeat(CurrentBeat);
|
||||
}
|
||||
|
||||
private static float[] GetNoteTimeBeforeBeat(int beat)
|
||||
private static float[] _GetNoteTimeBeforeBeat(int beat)
|
||||
{
|
||||
CSong song = GetSong();
|
||||
int StartBeat = (int)Math.Floor(beat - GetBeatFromTime(CSettings.PauseResetTime, song.BPM, 0f));
|
||||
int startBeat = (int)Math.Floor(beat - GetBeatFromTime(CSettings.PauseResetTime, song.BPM, 0f));
|
||||
int lastStart = 0;
|
||||
int nextStart = 0;
|
||||
foreach (CVoice voice in song.Notes.Voices)
|
||||
@@ -441,16 +434,13 @@ namespace Vocaluxe.Base
|
||||
{
|
||||
foreach (CSongNote note in line.Notes)
|
||||
{
|
||||
if (note.StartBeat > StartBeat)
|
||||
if (note.StartBeat > startBeat)
|
||||
{
|
||||
nextStartNote = note.StartBeat;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
voiceStart = note.StartBeat;
|
||||
lastEnd = note.EndBeat;
|
||||
}
|
||||
voiceStart = note.StartBeat;
|
||||
lastEnd = note.EndBeat;
|
||||
}
|
||||
if (nextStartNote > 0)
|
||||
break;
|
||||
|
||||
+35
-69
@@ -30,13 +30,11 @@ namespace Vocaluxe.Base
|
||||
{
|
||||
static class CGraphics
|
||||
{
|
||||
private static bool _Fading;
|
||||
private static Stopwatch _FadingTimer;
|
||||
private static CFading _Fading;
|
||||
private static readonly CCursor _Cursor = new CCursor();
|
||||
private static float _GlobalAlpha;
|
||||
private static float _ZOffset;
|
||||
|
||||
private static IMenu _OldScreen;
|
||||
private static EScreens _CurrentScreen;
|
||||
private static EScreens _NextScreen;
|
||||
private static EPopupScreens _CurrentPopupScreen;
|
||||
@@ -98,7 +96,6 @@ namespace Vocaluxe.Base
|
||||
_CurrentScreen = EScreens.ScreenLoad;
|
||||
_NextScreen = EScreens.ScreenNull;
|
||||
_CurrentPopupScreen = EPopupScreens.NoPopup;
|
||||
_FadingTimer = new Stopwatch();
|
||||
_VolumePopupTimer = new Stopwatch();
|
||||
|
||||
_GlobalAlpha = 1f;
|
||||
@@ -198,11 +195,9 @@ namespace Vocaluxe.Base
|
||||
|
||||
public static bool Draw()
|
||||
{
|
||||
if ((_NextScreen != EScreens.ScreenNull) && !_Fading)
|
||||
if (_NextScreen != EScreens.ScreenNull && _Fading == null)
|
||||
{
|
||||
_Fading = true;
|
||||
_FadingTimer.Reset();
|
||||
_FadingTimer.Start();
|
||||
_Fading = new CFading(0f, 1f, CConfig.FadeTime);
|
||||
|
||||
if (_NextScreen == EScreens.ScreenPartyDummy)
|
||||
{
|
||||
@@ -216,49 +211,29 @@ namespace Vocaluxe.Base
|
||||
HidePopup(EPopupScreens.PopupPlayerControl);
|
||||
}
|
||||
|
||||
if (_Fading)
|
||||
if (_Fading != null)
|
||||
{
|
||||
long fadeTime = (long)(CConfig.FadeTime * 1000);
|
||||
bool finished;
|
||||
float newAlpha = _Fading.GetValue(out finished);
|
||||
|
||||
if ((_FadingTimer.ElapsedMilliseconds < fadeTime) && (CConfig.FadeTime > 0))
|
||||
if (!finished)
|
||||
{
|
||||
long ms = 1;
|
||||
if (_FadingTimer.ElapsedMilliseconds > 0)
|
||||
ms = _FadingTimer.ElapsedMilliseconds;
|
||||
|
||||
float factor = (float)ms / fadeTime;
|
||||
|
||||
_GlobalAlpha = 1f; // -factor / 100f;
|
||||
_GlobalAlpha = 1f; // -newAlpha / 100f;
|
||||
_ZOffset = CSettings.ZFar / 2;
|
||||
|
||||
if (_CurrentScreen == EScreens.ScreenPartyDummy)
|
||||
{
|
||||
CFonts.PartyModeID = CParty.CurrentPartyModeID;
|
||||
_OldScreen.Draw();
|
||||
CFonts.PartyModeID = -1;
|
||||
}
|
||||
else
|
||||
_OldScreen.Draw();
|
||||
_DrawScreen(_CurrentScreen);
|
||||
|
||||
|
||||
_GlobalAlpha = factor;
|
||||
_GlobalAlpha = newAlpha;
|
||||
_ZOffset = 0f;
|
||||
|
||||
if (_NextScreen == EScreens.ScreenPartyDummy)
|
||||
{
|
||||
CFonts.PartyModeID = CParty.CurrentPartyModeID;
|
||||
_Screens[(int)_NextScreen].Draw();
|
||||
CFonts.PartyModeID = -1;
|
||||
}
|
||||
else
|
||||
_Screens[(int)_NextScreen].Draw();
|
||||
_DrawScreen(_NextScreen);
|
||||
|
||||
_GlobalAlpha = 1f;
|
||||
}
|
||||
else
|
||||
{
|
||||
_Screens[(int)_CurrentScreen].OnClose();
|
||||
GC.Collect();
|
||||
_CurrentScreen = _NextScreen;
|
||||
_NextScreen = EScreens.ScreenNull;
|
||||
if (CBackgroundMusic.IsPlaying)
|
||||
@@ -266,32 +241,13 @@ namespace Vocaluxe.Base
|
||||
_Screens[(int)_CurrentScreen].OnShowFinish();
|
||||
_Screens[(int)_CurrentScreen].ProcessMouseMove(_Cursor.X, _Cursor.Y);
|
||||
|
||||
if (_CurrentScreen == EScreens.ScreenPartyDummy)
|
||||
{
|
||||
CFonts.PartyModeID = CParty.CurrentPartyModeID;
|
||||
_Screens[(int)_CurrentScreen].Draw();
|
||||
CFonts.PartyModeID = -1;
|
||||
}
|
||||
else
|
||||
_Screens[(int)_CurrentScreen].Draw();
|
||||
_DrawScreen(_CurrentScreen);
|
||||
|
||||
_Fading = false;
|
||||
_FadingTimer.Stop();
|
||||
_Fading = null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_CurrentScreen == EScreens.ScreenPartyDummy)
|
||||
{
|
||||
CFonts.PartyModeID = CParty.CurrentPartyModeID;
|
||||
_Screens[(int)_CurrentScreen].Draw();
|
||||
CFonts.PartyModeID = -1;
|
||||
}
|
||||
else
|
||||
_Screens[(int)_CurrentScreen].Draw();
|
||||
|
||||
_OldScreen = _Screens[(int)_CurrentScreen];
|
||||
}
|
||||
_DrawScreen(_CurrentScreen);
|
||||
|
||||
foreach (IMenu popup in _PopupScreens)
|
||||
popup.Draw();
|
||||
@@ -302,6 +258,18 @@ namespace Vocaluxe.Base
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void _DrawScreen(EScreens screen)
|
||||
{
|
||||
if (screen == EScreens.ScreenPartyDummy)
|
||||
{
|
||||
CFonts.PartyModeID = CParty.CurrentPartyModeID;
|
||||
_Screens[(int)screen].Draw();
|
||||
CFonts.PartyModeID = -1;
|
||||
}
|
||||
else
|
||||
_Screens[(int)screen].Draw();
|
||||
}
|
||||
|
||||
public static void FadeTo(EScreens screen)
|
||||
{
|
||||
if (screen == EScreens.ScreenPartyDummy)
|
||||
@@ -404,9 +372,6 @@ namespace Vocaluxe.Base
|
||||
CConfig.BorderTop = 0;
|
||||
CConfig.BorderBottom = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
CConfig.SaveConfig();
|
||||
break;
|
||||
@@ -486,8 +451,7 @@ namespace Vocaluxe.Base
|
||||
if (_CurrentPopupScreen == EPopupScreens.NoPopup && diff != 0)
|
||||
{
|
||||
ShowPopup(EPopupScreens.PopupVolumeControl);
|
||||
_VolumePopupTimer.Reset();
|
||||
_VolumePopupTimer.Start();
|
||||
_VolumePopupTimer.Restart();
|
||||
}
|
||||
|
||||
CBackgroundMusic.ApplyVolume();
|
||||
@@ -501,7 +465,7 @@ namespace Vocaluxe.Base
|
||||
CDraw.MakeScreenShot();
|
||||
else
|
||||
{
|
||||
if (!_Fading)
|
||||
if (_Fading == null)
|
||||
{
|
||||
bool handled = false;
|
||||
if (_CurrentPopupScreen != EPopupScreens.NoPopup)
|
||||
@@ -565,12 +529,14 @@ namespace Vocaluxe.Base
|
||||
|
||||
bool handled = false;
|
||||
if (_CurrentPopupScreen != EPopupScreens.NoPopup)
|
||||
{
|
||||
handled = _PopupScreens[(int)_CurrentPopupScreen].HandleMouse(mouseEvent);
|
||||
|
||||
if (handled && _CurrentPopupScreen == EPopupScreens.PopupVolumeControl)
|
||||
_Screens[(int)_CurrentScreen].ApplyVolume();
|
||||
if (handled && _CurrentPopupScreen == EPopupScreens.PopupVolumeControl)
|
||||
_Screens[(int)_CurrentScreen].ApplyVolume();
|
||||
}
|
||||
|
||||
if (!handled && !_Fading && (_Cursor.IsActive || mouseEvent.LB || mouseEvent.RB || mouseEvent.MB))
|
||||
if (!handled && _Fading == null && (_Cursor.IsActive || mouseEvent.LB || mouseEvent.RB || mouseEvent.MB))
|
||||
resume &= _Screens[(int)_CurrentScreen].HandleMouse(mouseEvent);
|
||||
|
||||
if (!eventsAvailable)
|
||||
@@ -597,14 +563,14 @@ namespace Vocaluxe.Base
|
||||
CDraw.MakeScreenShot();
|
||||
else
|
||||
{
|
||||
if (!_Fading)
|
||||
if (_Fading == null)
|
||||
_Screens[(int)_CurrentScreen].HandleInputThemeEditor(keyEvent);
|
||||
}
|
||||
}
|
||||
|
||||
while (mouse.PollEvent(ref mouseEvent))
|
||||
{
|
||||
if (!_Fading)
|
||||
if (_Fading == null)
|
||||
_Screens[(int)_CurrentScreen].HandleMouseThemeEditor(mouseEvent);
|
||||
|
||||
_UpdateMousePosition(mouseEvent.X, mouseEvent.Y);
|
||||
|
||||
+58
-25
@@ -28,6 +28,7 @@ namespace Vocaluxe.Base
|
||||
private readonly string _LogFileName;
|
||||
private readonly string _LogName;
|
||||
private StreamWriter _LogFile;
|
||||
private readonly Object _FileMutex = new Object();
|
||||
|
||||
public CLogFile(string fileName, string logName)
|
||||
{
|
||||
@@ -37,26 +38,34 @@ namespace Vocaluxe.Base
|
||||
|
||||
private void _Open()
|
||||
{
|
||||
_LogFile = new StreamWriter(Path.Combine(CSettings.DataPath, _LogFileName), false, Encoding.UTF8);
|
||||
lock (_FileMutex)
|
||||
{
|
||||
if (_LogFile != null)
|
||||
return;
|
||||
_LogFile = new StreamWriter(Path.Combine(CSettings.DataPath, _LogFileName), false, Encoding.UTF8);
|
||||
|
||||
_LogFile.WriteLine(_LogName + " " + CSettings.GetFullVersionText() + " " + DateTime.Now);
|
||||
_LogFile.WriteLine("----------------------------------------");
|
||||
_LogFile.WriteLine();
|
||||
_LogFile.WriteLine(_LogName + " " + CSettings.GetFullVersionText() + " " + DateTime.Now);
|
||||
_LogFile.WriteLine("----------------------------------------");
|
||||
_LogFile.WriteLine();
|
||||
}
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
if (_LogFile == null)
|
||||
return;
|
||||
try
|
||||
lock (_FileMutex)
|
||||
{
|
||||
_LogFile.Flush();
|
||||
_LogFile.Close();
|
||||
if (_LogFile == null)
|
||||
return;
|
||||
try
|
||||
{
|
||||
_LogFile.Flush();
|
||||
_LogFile.Close();
|
||||
}
|
||||
catch (Exception) {}
|
||||
}
|
||||
catch (Exception) {}
|
||||
}
|
||||
|
||||
public void Add(string text)
|
||||
public virtual void Add(string text)
|
||||
{
|
||||
if (_LogFile == null)
|
||||
_Open();
|
||||
@@ -69,15 +78,28 @@ namespace Vocaluxe.Base
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_LogFile != null)
|
||||
{
|
||||
_LogFile.Dispose();
|
||||
_LogFile = null;
|
||||
}
|
||||
Close();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
|
||||
class CErrorLogFile : CLogFile
|
||||
{
|
||||
private int _NumErrors;
|
||||
private readonly Object _WriteMutex = new Object();
|
||||
|
||||
public CErrorLogFile(string fileName, string logName) : base(fileName, logName) {}
|
||||
|
||||
public override void Add(string errorText)
|
||||
{
|
||||
lock (_WriteMutex)
|
||||
{
|
||||
_NumErrors++;
|
||||
base.Add(_NumErrors + ") " + errorText);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class CLog
|
||||
{
|
||||
private const int _MaxBenchmarks = 10;
|
||||
@@ -85,18 +107,20 @@ namespace Vocaluxe.Base
|
||||
private static CLogFile _ErrorLog;
|
||||
private static CLogFile _PerformanceLog;
|
||||
private static CLogFile _BenchmarkLog;
|
||||
private static CLogFile _DebugLog;
|
||||
private static CLogFile _SongInfoLog;
|
||||
|
||||
private static int _NumErrors;
|
||||
private static Stopwatch[] _BenchmarkTimer;
|
||||
private static readonly double _NanosecPerTick = (1000.0 * 1000.0 * 1000.0) / Stopwatch.Frequency;
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
_ErrorLog = new CLogFile(CSettings.FileErrorLog, "ErrorLog");
|
||||
_PerformanceLog = new CLogFile(CSettings.FilePerformanceLog, "PerformanceLog");
|
||||
_BenchmarkLog = new CLogFile(CSettings.FileBenchmarkLog, "BenchmarkLog");
|
||||
_ErrorLog = new CErrorLogFile(CSettings.FileErrorLog, "Error-Log");
|
||||
_PerformanceLog = new CLogFile(CSettings.FilePerformanceLog, "Performance-Log");
|
||||
_BenchmarkLog = new CLogFile(CSettings.FileBenchmarkLog, "Benchmark-Log");
|
||||
_DebugLog = new CLogFile(CSettings.FileDebugLog, "Debug-Log");
|
||||
_SongInfoLog = new CLogFile(CSettings.FileSongInfoLog, "Song-Information-Log");
|
||||
|
||||
_NumErrors = 0;
|
||||
_BenchmarkTimer = new Stopwatch[_MaxBenchmarks];
|
||||
for (int i = 0; i < _BenchmarkTimer.Length; i++)
|
||||
_BenchmarkTimer[i] = new Stopwatch();
|
||||
@@ -107,29 +131,38 @@ namespace Vocaluxe.Base
|
||||
_ErrorLog.Close();
|
||||
_PerformanceLog.Close();
|
||||
_BenchmarkLog.Close();
|
||||
_DebugLog.Close();
|
||||
_SongInfoLog.Close();
|
||||
}
|
||||
|
||||
#region LogError
|
||||
public static void LogError(string errorText, bool show = false, bool exit = false, Exception e = null)
|
||||
{
|
||||
_NumErrors++;
|
||||
if (show)
|
||||
MessageBox.Show(errorText, CSettings.ProgramName, MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
if (e != null)
|
||||
errorText += ": " + e;
|
||||
_ErrorLog.Add(_NumErrors + ") " + errorText);
|
||||
_ErrorLog.Add(errorText);
|
||||
if (exit)
|
||||
Environment.Exit(Environment.ExitCode);
|
||||
}
|
||||
#endregion LogError
|
||||
|
||||
#region LogPerformance
|
||||
public static void LogDebug(string text)
|
||||
{
|
||||
_DebugLog.Add(String.Format("{0:HH:mm:ss.ffff}", DateTime.Now) + ":" + text);
|
||||
}
|
||||
|
||||
public static void LogSongInfo(string text)
|
||||
{
|
||||
_SongInfoLog.Add(text);
|
||||
}
|
||||
|
||||
public static void LogPerformance(string text)
|
||||
{
|
||||
_PerformanceLog.Add(text);
|
||||
_PerformanceLog.Add("-------------------------------");
|
||||
}
|
||||
#endregion LogPerformance
|
||||
|
||||
#region LogBenchmark
|
||||
public static void StartBenchmark(int benchmarkNr, string text)
|
||||
|
||||
@@ -443,6 +443,16 @@ namespace Vocaluxe.Base
|
||||
{
|
||||
CLog.LogError(errorText);
|
||||
}
|
||||
|
||||
public void LogDebug(string text)
|
||||
{
|
||||
CLog.LogDebug(text);
|
||||
}
|
||||
|
||||
public void LogSongInfo(string text)
|
||||
{
|
||||
CLog.LogSongInfo(text);
|
||||
}
|
||||
}
|
||||
|
||||
class CBfonts : IFonts
|
||||
|
||||
@@ -85,6 +85,8 @@ namespace Vocaluxe.Base
|
||||
public const string FilePerformanceLog = "Performance.log";
|
||||
public const string FileErrorLog = "Error.log";
|
||||
public const string FileBenchmarkLog = "Benchmark.log";
|
||||
public const string FileDebugLog = "Debug.log";
|
||||
public const string FileSongInfoLog = "SongInformation.log";
|
||||
|
||||
public const string SoundT440 = "440Hz.mp3";
|
||||
|
||||
@@ -102,7 +104,7 @@ namespace Vocaluxe.Base
|
||||
#endif
|
||||
Path.Combine(DataPath, FolderProfiles)
|
||||
};
|
||||
public static string FolderPhotos = "Photos";
|
||||
public const string FolderPhotos = "Photos";
|
||||
public const string FolderSongs = "Songs";
|
||||
public const string FolderSounds = "Sounds";
|
||||
public const string FolderLanguages = "Languages";
|
||||
@@ -127,7 +129,7 @@ namespace Vocaluxe.Base
|
||||
|
||||
public const int NumNoteLines = 11;
|
||||
public static int MouseMoveDiffMin = 2;
|
||||
public const float MouseMoveOffTime = 3f;
|
||||
public const int MouseMoveOffTime = 3000; //in ms
|
||||
|
||||
public const int MaxNumPlayer = 6;
|
||||
public const int MaxScore = 10000;
|
||||
|
||||
@@ -221,9 +221,7 @@ namespace Vocaluxe.Base
|
||||
return;
|
||||
|
||||
//Calc avarage sing-count
|
||||
int totalCounts = 0;
|
||||
foreach (CSong song in VisibleSongs)
|
||||
totalCounts += song.NumPlayedSession;
|
||||
int totalCounts = VisibleSongs.Sum(song => song.NumPlayedSession);
|
||||
int averageCount = totalCounts / NumSongsVisible;
|
||||
|
||||
foreach (CSong song in VisibleSongs)
|
||||
|
||||
+9
-426
@@ -17,7 +17,6 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using Vocaluxe.Lib.Sound;
|
||||
using VocaluxeLib;
|
||||
@@ -181,7 +180,7 @@ namespace Vocaluxe.Base
|
||||
#endregion Playback
|
||||
|
||||
#region Sounds
|
||||
public static int PlaySound(ESounds sound)
|
||||
public static int PlaySound(ESounds sound, bool fade = true)
|
||||
{
|
||||
string file = Path.Combine(Environment.CurrentDirectory, CSettings.FolderSounds);
|
||||
switch (sound)
|
||||
@@ -189,15 +188,18 @@ namespace Vocaluxe.Base
|
||||
case ESounds.T440:
|
||||
file = Path.Combine(file, CSettings.SoundT440);
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (file == "")
|
||||
if (!File.Exists(file))
|
||||
return -1;
|
||||
|
||||
int stream = Load(file);
|
||||
int stream = Load(file, true);
|
||||
float length = GetLength(stream);
|
||||
Play(stream);
|
||||
FadeAndClose(stream, 100f, length);
|
||||
if (fade)
|
||||
FadeAndClose(stream, 100f, length);
|
||||
return stream;
|
||||
}
|
||||
#endregion Sounds
|
||||
@@ -205,26 +207,21 @@ namespace Vocaluxe.Base
|
||||
#region Record
|
||||
private static IRecord _Record;
|
||||
|
||||
public static bool RecordInit()
|
||||
public static void RecordInit()
|
||||
{
|
||||
switch (CConfig.RecordLib)
|
||||
{
|
||||
case ERecordLib.PortAudio:
|
||||
_Record = new CPortAudioRecord();
|
||||
break;
|
||||
|
||||
#if WIN
|
||||
case ERecordLib.DirectSound:
|
||||
_Record = new CDirectSoundRecord();
|
||||
break;
|
||||
#endif
|
||||
|
||||
// case ERecordLib.PortAudio:
|
||||
default:
|
||||
_Record = new CPortAudioRecord();
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void RecordCloseAll()
|
||||
@@ -313,418 +310,4 @@ namespace Vocaluxe.Base
|
||||
}
|
||||
#endregion Record
|
||||
}
|
||||
|
||||
class CBuffer : IDisposable
|
||||
{
|
||||
private const double _BaseToneFreq = 65.4064;
|
||||
private const int _NumHalfTones = 47;
|
||||
|
||||
private readonly float[] _ToneWeigth;
|
||||
private Int16[] _AnalysisBuffer = new Int16[4096];
|
||||
private readonly Object _AnalysisBufferLock = new Object();
|
||||
|
||||
private bool _ToneValid;
|
||||
private int _Tone;
|
||||
private int _ToneAbs;
|
||||
private double _MaxVolume;
|
||||
private bool _NewSamples;
|
||||
|
||||
private MemoryStream _Stream; // full buffer
|
||||
|
||||
public CBuffer()
|
||||
{
|
||||
_ToneWeigth = new float[_NumHalfTones];
|
||||
for (int i = 0; i < _ToneWeigth.Length; i++)
|
||||
_ToneWeigth[i] = 0.99f;
|
||||
_Stream = new MemoryStream();
|
||||
_NewSamples = false;
|
||||
}
|
||||
|
||||
public int NumHalfTones
|
||||
{
|
||||
get { return _NumHalfTones; }
|
||||
}
|
||||
|
||||
public int ToneAbs
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (_AnalysisBufferLock)
|
||||
{
|
||||
return _ToneAbs;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int Tone
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (_AnalysisBufferLock)
|
||||
{
|
||||
return _Tone;
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
lock (_AnalysisBufferLock)
|
||||
{
|
||||
_Tone = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public float MaxVolume
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (_AnalysisBufferLock)
|
||||
{
|
||||
return (float)_MaxVolume;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool ToneValid
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (_AnalysisBufferLock)
|
||||
{
|
||||
return _ToneValid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public long Length
|
||||
{
|
||||
get { return _Stream.Length; }
|
||||
}
|
||||
|
||||
public byte[] Buffer
|
||||
{
|
||||
get { return _Stream.ToArray(); }
|
||||
}
|
||||
|
||||
public float[] ToneWeigth
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (_AnalysisBufferLock)
|
||||
{
|
||||
return _ToneWeigth;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_Stream.SetLength(0L);
|
||||
_AnalysisBuffer = new Int16[_AnalysisBuffer.Length];
|
||||
_ToneValid = false;
|
||||
_ToneAbs = 0;
|
||||
_Tone = 0;
|
||||
_NewSamples = false;
|
||||
}
|
||||
|
||||
public void Add(byte[] bytes)
|
||||
{
|
||||
_Stream.Write(bytes, 0, bytes.Length);
|
||||
}
|
||||
|
||||
public void ProcessNewBuffer(byte[] buffer)
|
||||
{
|
||||
// apply software boost
|
||||
//BoostBuffer(Buffer, BufferSize);
|
||||
|
||||
// voice passthrough (send data to playback-device)
|
||||
//if (assigned(fVoiceStream)) then
|
||||
//fVoiceStream.WriteData(Buffer, BufferSize);
|
||||
lock (_AnalysisBufferLock)
|
||||
{
|
||||
Add(buffer);
|
||||
_NewSamples = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void AnalyzeBuffer()
|
||||
{
|
||||
if (!_NewSamples)
|
||||
return;
|
||||
|
||||
lock (_AnalysisBufferLock)
|
||||
{
|
||||
int len = _AnalysisBuffer.Length * 2;
|
||||
if (_Stream.Length >= len)
|
||||
{
|
||||
var buf = new byte[len];
|
||||
_Stream.Position -= len;
|
||||
_Stream.Read(buf, 0, len);
|
||||
|
||||
var b = new byte[2];
|
||||
for (int i = 0; i < _AnalysisBuffer.Length; i++)
|
||||
{
|
||||
b[0] = buf[i * 2];
|
||||
b[1] = buf[i * 2 + 1];
|
||||
|
||||
_AnalysisBuffer[i] = BitConverter.ToInt16(b, 0);
|
||||
}
|
||||
}
|
||||
_NewSamples = false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// find maximum volume
|
||||
_MaxVolume = 0;
|
||||
for (int i = 0; i < _AnalysisBuffer.Length / 4; i++)
|
||||
{
|
||||
float volume = Math.Abs((float)_AnalysisBuffer[i]) / Int16.MaxValue;
|
||||
if (volume > MaxVolume)
|
||||
_MaxVolume = volume;
|
||||
}
|
||||
|
||||
_AnalyzeByAutocorrelation(_MaxVolume >= 0.02f);
|
||||
}
|
||||
catch (Exception) {}
|
||||
}
|
||||
|
||||
private void _AnalyzeByAutocorrelation(bool valid)
|
||||
{
|
||||
if (!valid)
|
||||
{
|
||||
_ToneValid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
const double halftoneBase = 1.05946309436; // 2^(1/12) -> HalftoneBase^12 = 2 (one octave)
|
||||
|
||||
// prepare to analyze
|
||||
double maxWeight = -1.0;
|
||||
double minWeight = 1.0;
|
||||
int maxTone = -1;
|
||||
var weigth = new float[_NumHalfTones];
|
||||
|
||||
// analyze halftones
|
||||
// Note: at the lowest tone (~65Hz) and a buffer-size of 4096
|
||||
// at 44.1 (or 48kHz) only 6 (or 5) samples are compared, this might be
|
||||
// too few samples -> use a bigger buffer-size
|
||||
for (int toneIndex = 0; toneIndex < _NumHalfTones; toneIndex++)
|
||||
{
|
||||
double curFreq = _BaseToneFreq * Math.Pow(halftoneBase, toneIndex);
|
||||
double curWeight = _AnalyzeAutocorrelationFreq(curFreq);
|
||||
|
||||
if (curWeight > maxWeight)
|
||||
{
|
||||
maxWeight = curWeight;
|
||||
maxTone = toneIndex;
|
||||
}
|
||||
|
||||
if (curWeight < minWeight)
|
||||
minWeight = curWeight;
|
||||
|
||||
weigth[toneIndex] = (float)curWeight;
|
||||
}
|
||||
|
||||
if (maxWeight - minWeight > 0.01)
|
||||
{
|
||||
for (int i = 0; i < weigth.Length; i++)
|
||||
_ToneWeigth[i] = weigth[i];
|
||||
|
||||
_ToneAbs = maxTone;
|
||||
_Tone = maxTone % 12;
|
||||
_ToneValid = true;
|
||||
}
|
||||
else
|
||||
_ToneValid = false;
|
||||
}
|
||||
|
||||
private double _AnalyzeAutocorrelationFreq(double freq)
|
||||
{
|
||||
int sampleIndex = 0; // index of sample to analyze
|
||||
var samplesPerPeriod = (int)Math.Round(44100.0 / freq); // samples in one period
|
||||
int correlatingSampleIndex = sampleIndex + samplesPerPeriod; // index of sample one period ahead
|
||||
|
||||
double accumDist = 0.0; // accumulated distances
|
||||
|
||||
// compare correlating samples
|
||||
while (correlatingSampleIndex < _AnalysisBuffer.Length)
|
||||
{
|
||||
// calc distance (correlation: 1-dist) to corresponding sample in next period
|
||||
// distance (0=equal .. 1=totally different) between correlated samples
|
||||
double dist = Math.Abs((double)_AnalysisBuffer[sampleIndex] - _AnalysisBuffer[correlatingSampleIndex]) / Int16.MaxValue;
|
||||
accumDist += dist;
|
||||
sampleIndex++;
|
||||
correlatingSampleIndex++;
|
||||
}
|
||||
|
||||
return 1 - accumDist / _AnalysisBuffer.Length;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_Stream != null)
|
||||
{
|
||||
_Stream.Dispose();
|
||||
_Stream = null;
|
||||
}
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
|
||||
class CSyncTimer
|
||||
{
|
||||
private readonly CPt1 _ExternTime;
|
||||
private readonly Stopwatch _Timer;
|
||||
private float _SetValue;
|
||||
|
||||
public float Time
|
||||
{
|
||||
get
|
||||
{
|
||||
double nanosecPerTick = (1000.0 * 1000.0 * 1000.0) / Stopwatch.Frequency;
|
||||
long ticks = _Timer.ElapsedTicks;
|
||||
float dt = _Timer.ElapsedMilliseconds / 1000f;
|
||||
|
||||
if (Stopwatch.IsHighResolution && ticks != 0)
|
||||
dt = (float)(ticks * nanosecPerTick / 1000000000.0);
|
||||
|
||||
return _SetValue + dt;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
_ExternTime.Time = value;
|
||||
_SetValue = value;
|
||||
_Timer.Reset();
|
||||
_Timer.Start();
|
||||
}
|
||||
}
|
||||
|
||||
public CSyncTimer(float currentTime, float k, float t)
|
||||
{
|
||||
_ExternTime = new CPt1(currentTime, k, t);
|
||||
_Timer = new Stopwatch();
|
||||
_SetValue = currentTime;
|
||||
}
|
||||
|
||||
public float Update(float newTime)
|
||||
{
|
||||
float et = _ExternTime.Update(newTime);
|
||||
|
||||
float dt = Time;
|
||||
|
||||
float diff = et - dt;
|
||||
if (Math.Abs(diff) > 0.05f)
|
||||
{
|
||||
_Timer.Reset();
|
||||
_Timer.Start();
|
||||
_SetValue = dt + diff;
|
||||
dt = _SetValue;
|
||||
//Console.WriteLine("DRIFTED!!! " + diff.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (diff > 0.01f)
|
||||
_SetValue += 0.000025f;
|
||||
|
||||
if (diff < -0.01f)
|
||||
_SetValue -= 0.000025f;
|
||||
}
|
||||
//Console.WriteLine(diff.ToString());
|
||||
return dt;
|
||||
}
|
||||
|
||||
public void Pause()
|
||||
{
|
||||
_ExternTime.Pause();
|
||||
_Timer.Stop();
|
||||
}
|
||||
|
||||
public void Resume()
|
||||
{
|
||||
_ExternTime.Resume();
|
||||
_Timer.Start();
|
||||
}
|
||||
}
|
||||
|
||||
class CPt1
|
||||
{
|
||||
private float _CurrentTime;
|
||||
private float _OldTime;
|
||||
|
||||
private readonly Stopwatch _Timer;
|
||||
private readonly float _K;
|
||||
private readonly float _T;
|
||||
|
||||
public float Time
|
||||
{
|
||||
get
|
||||
{
|
||||
double nanosecPerTick = (1000.0 * 1000.0 * 1000.0) / Stopwatch.Frequency;
|
||||
long ticks = _Timer.ElapsedTicks;
|
||||
float dt = _Timer.ElapsedMilliseconds / 1000f;
|
||||
|
||||
if (Stopwatch.IsHighResolution && ticks != 0)
|
||||
dt = (float)(ticks * nanosecPerTick / 1000000000.0);
|
||||
|
||||
return _CurrentTime + dt;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (value < 0f)
|
||||
return;
|
||||
|
||||
_CurrentTime = value;
|
||||
_OldTime = value;
|
||||
_Timer.Reset();
|
||||
_Timer.Start();
|
||||
}
|
||||
}
|
||||
|
||||
public CPt1(float currentTime, float k, float t)
|
||||
{
|
||||
_CurrentTime = currentTime;
|
||||
_OldTime = currentTime;
|
||||
|
||||
_Timer = new Stopwatch();
|
||||
_K = k;
|
||||
_T = t;
|
||||
}
|
||||
|
||||
public float Update(float newTime)
|
||||
{
|
||||
_Timer.Stop();
|
||||
|
||||
double nanosecPerTick = (1000.0 * 1000.0 * 1000.0) / Stopwatch.Frequency;
|
||||
long ticks = _Timer.ElapsedTicks;
|
||||
float dt = _Timer.ElapsedMilliseconds / 1000f;
|
||||
|
||||
if (Stopwatch.IsHighResolution && ticks != 0)
|
||||
dt = (float)(ticks * nanosecPerTick / 1000000000.0);
|
||||
|
||||
float ts = 0f;
|
||||
if (dt > 0)
|
||||
ts = 1 / (_T / dt + 1);
|
||||
|
||||
_CurrentTime = ts * (_K * newTime - _OldTime) + _OldTime;
|
||||
_OldTime = _CurrentTime;
|
||||
|
||||
_Timer.Reset();
|
||||
_Timer.Start();
|
||||
|
||||
return _CurrentTime;
|
||||
}
|
||||
|
||||
public void Pause()
|
||||
{
|
||||
_Timer.Stop();
|
||||
}
|
||||
|
||||
public void Resume()
|
||||
{
|
||||
_Timer.Start();
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-12
@@ -18,7 +18,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
using System.Xml;
|
||||
using Vocaluxe.Base.Fonts;
|
||||
@@ -789,14 +788,8 @@ namespace Vocaluxe.Base
|
||||
|
||||
public static SColorF GetPlayerColor(int playerNr)
|
||||
{
|
||||
var color = new SColorF(1f, 1f, 1f, 1f);
|
||||
|
||||
int skinIndex = GetSkinIndex(-1);
|
||||
|
||||
if (_Skins[skinIndex].ThemeColors.Player.Length < playerNr)
|
||||
return color;
|
||||
|
||||
return _Skins[skinIndex].ThemeColors.Player[playerNr - 1];
|
||||
bool dummy;
|
||||
return GetPlayerColor(playerNr, out dummy);
|
||||
}
|
||||
|
||||
public static SColorF GetPlayerColor(string playerNrString)
|
||||
@@ -823,9 +816,6 @@ namespace Vocaluxe.Base
|
||||
{
|
||||
success = false;
|
||||
|
||||
if (_Skins[skinIndex].PartyModeID != -1)
|
||||
skinIndex = GetSkinIndex(-1);
|
||||
|
||||
if (_Skins[skinIndex].ThemeColors.Player.Length < playerNr || playerNr < 1)
|
||||
return new SColorF(1f, 1f, 1f, 1f);
|
||||
|
||||
|
||||
@@ -135,6 +135,7 @@ namespace Vocaluxe.Base
|
||||
{
|
||||
_VideoStream = CVideo.Load(CTheme.GetVideoFilePath(videoName, -1));
|
||||
_Loaded = true;
|
||||
CVideo.Pause(_VideoStream);
|
||||
}
|
||||
|
||||
public void Start()
|
||||
@@ -143,15 +144,18 @@ namespace Vocaluxe.Base
|
||||
_Finished = false;
|
||||
//CVideo.VdSkip(_VideoStream, 0f, 0f);
|
||||
_VideoTimer.Start();
|
||||
CVideo.Resume(_VideoStream);
|
||||
}
|
||||
|
||||
public void Pause()
|
||||
{
|
||||
CVideo.Pause(_VideoStream);
|
||||
_VideoTimer.Stop();
|
||||
}
|
||||
|
||||
public void Resume()
|
||||
{
|
||||
CVideo.Resume(_VideoStream);
|
||||
_VideoTimer.Start();
|
||||
}
|
||||
|
||||
@@ -175,6 +179,9 @@ namespace Vocaluxe.Base
|
||||
|
||||
public void PreLoad()
|
||||
{
|
||||
bool paused = _VideoTimer.IsRunning;
|
||||
if (paused)
|
||||
CVideo.Resume(_VideoStream);
|
||||
float videoTime = 0f;
|
||||
while (_VideoTexture == null && videoTime < 1f)
|
||||
{
|
||||
@@ -182,6 +189,8 @@ namespace Vocaluxe.Base
|
||||
CVideo.GetFrame(_VideoStream, ref _VideoTexture, 0, out dummy);
|
||||
videoTime += 0.05f;
|
||||
}
|
||||
if (paused)
|
||||
CVideo.Pause(_VideoStream);
|
||||
}
|
||||
|
||||
public void Close()
|
||||
|
||||
@@ -96,9 +96,8 @@ namespace Vocaluxe.Base.Server
|
||||
var stream = new MemoryStream();
|
||||
stream.Write(cmd, 0, cmd.Length);
|
||||
|
||||
byte[] data;
|
||||
string json = JsonConvert.SerializeObject(obj);
|
||||
data = _Encoder.GetBytes(json);
|
||||
byte[] data = _Encoder.GetBytes(json);
|
||||
stream.Write(data, 0, data.Length);
|
||||
return stream.ToArray();
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@ using ServerLib;
|
||||
using Vocaluxe.Lib.Input;
|
||||
using Vocaluxe.Lib.Playlist;
|
||||
using VocaluxeLib;
|
||||
using VocaluxeLib.Draw;
|
||||
using VocaluxeLib.Menu;
|
||||
using VocaluxeLib.Profile;
|
||||
using VocaluxeLib.Songs;
|
||||
@@ -314,7 +313,7 @@ namespace Vocaluxe.Base.Server
|
||||
#endregion
|
||||
|
||||
#region photo
|
||||
private static List<string> photosOfThisRound = new List<string>();
|
||||
private static readonly List<string> _PhotosOfThisRound = new List<string>();
|
||||
|
||||
private static bool _SendPhoto(SPhotoData photoData)
|
||||
{
|
||||
@@ -325,17 +324,17 @@ namespace Vocaluxe.Base.Server
|
||||
string filePath = _SaveImage(photoData.Photo, name, CSettings.FolderPhotos);
|
||||
if (!string.IsNullOrEmpty(filePath))
|
||||
{
|
||||
photosOfThisRound.Add(filePath);
|
||||
_PhotosOfThisRound.Add(filePath);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal static string[] getPhotosOfThisRound()
|
||||
internal static string[] GetPhotosOfThisRound()
|
||||
{
|
||||
string[] result = photosOfThisRound.ToArray();
|
||||
photosOfThisRound.Clear();
|
||||
string[] result = _PhotosOfThisRound.ToArray();
|
||||
_PhotosOfThisRound.Clear();
|
||||
return result;
|
||||
}
|
||||
#endregion
|
||||
@@ -583,11 +582,11 @@ namespace Vocaluxe.Base.Server
|
||||
return false;
|
||||
}
|
||||
|
||||
byte[] salt = profile.PasswordSalt;
|
||||
//byte[] salt = profile.PasswordSalt;
|
||||
return hashedPassword.SequenceEqual(profile.PasswordHash);
|
||||
}
|
||||
|
||||
private static byte[] _GetPassowordSalt(int profileId)
|
||||
private static byte[] _GetPasswordSalt(int profileId)
|
||||
{
|
||||
CProfile profile = CProfiles.GetProfile(profileId);
|
||||
if (profile == null)
|
||||
|
||||
@@ -16,12 +16,8 @@
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Security;
|
||||
using System.Text;
|
||||
using Microsoft.Win32;
|
||||
using Vocaluxe.Base;
|
||||
|
||||
|
||||
@@ -161,25 +161,25 @@ namespace Vocaluxe.Lib.Input
|
||||
public static int ReadTimeout(IntPtr device, ref byte[] data, int length, int milliseconds)
|
||||
{
|
||||
IntPtr dataPtr = Marshal.AllocHGlobal(length);
|
||||
int result;
|
||||
int bytesRead;
|
||||
try
|
||||
{
|
||||
result = hid_read_timeout(device, dataPtr, length, milliseconds);
|
||||
bytesRead = hid_read_timeout(device, dataPtr, length, milliseconds);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
result = -1;
|
||||
bytesRead = -1;
|
||||
CLog.LogError("Error CHIDAPI.ReadTimeout(): " + e);
|
||||
}
|
||||
|
||||
if (result != -1)
|
||||
Marshal.Copy(dataPtr, data, 0, result);
|
||||
if (bytesRead != -1)
|
||||
Marshal.Copy(dataPtr, data, 0, bytesRead);
|
||||
else
|
||||
data = null;
|
||||
|
||||
Marshal.FreeHGlobal(dataPtr);
|
||||
|
||||
return result;
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
[DllImport(_HIDApiDll, ExactSpelling = false, CallingConvention = CallingConvention.Cdecl, EntryPoint = "hid_read", CharSet = CharSet.Unicode)]
|
||||
|
||||
@@ -25,7 +25,7 @@ using VocaluxeLib;
|
||||
|
||||
namespace Vocaluxe.Lib.Input.WiiMote
|
||||
{
|
||||
class CWiiMote : IController, IDisposable
|
||||
class CWiiMote : IController
|
||||
{
|
||||
private CWiiMoteLib _WiiMote;
|
||||
|
||||
@@ -54,7 +54,7 @@ namespace Vocaluxe.Lib.Input.WiiMote
|
||||
_RumbleTimer = new CRumbleTimer();
|
||||
_Gesture = new CGesture();
|
||||
|
||||
_HandlerThread = new Thread(_MainLoop) {Priority = ThreadPriority.BelowNormal};
|
||||
_HandlerThread = new Thread(_MainLoop) {Name = "WiiMote", Priority = ThreadPriority.BelowNormal};
|
||||
|
||||
_KeysPool = new List<SKeyEvent>();
|
||||
_CurrentKeysPool = new List<SKeyEvent>();
|
||||
@@ -151,8 +151,7 @@ namespace Vocaluxe.Lib.Input.WiiMote
|
||||
|
||||
if (startRumble)
|
||||
_WiiMote.SetRumble(true);
|
||||
|
||||
if (stopRumble)
|
||||
else if (stopRumble)
|
||||
_WiiMote.SetRumble(false);
|
||||
}
|
||||
}
|
||||
@@ -314,15 +313,5 @@ namespace Vocaluxe.Lib.Input.WiiMote
|
||||
_MousePool.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_WiiMote != null)
|
||||
{
|
||||
_WiiMote.Dispose();
|
||||
_WiiMote = null;
|
||||
}
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -137,7 +137,7 @@ namespace Vocaluxe.Lib.Input.WiiMote
|
||||
}
|
||||
#endregion Events
|
||||
|
||||
public sealed class CWiiMoteLib : IDisposable
|
||||
public sealed class CWiiMoteLib
|
||||
{
|
||||
// ReSharper disable InconsistentNaming
|
||||
private const ushort _VID = 0x057e;
|
||||
@@ -178,8 +178,7 @@ namespace Vocaluxe.Lib.Input.WiiMote
|
||||
private int _Address;
|
||||
private short _Size;
|
||||
|
||||
private readonly Thread _Reader;
|
||||
private bool _Active;
|
||||
private Thread _Reader;
|
||||
private readonly bool _Error;
|
||||
|
||||
public bool Connected { get; private set; }
|
||||
@@ -191,72 +190,63 @@ namespace Vocaluxe.Lib.Input.WiiMote
|
||||
#region Interface
|
||||
public CWiiMoteLib()
|
||||
{
|
||||
Connected = false;
|
||||
_Active = true;
|
||||
_Error = false;
|
||||
_Reader = new Thread(_ReaderLoop);
|
||||
_Reader.Start();
|
||||
|
||||
if (!CHIDApi.Init())
|
||||
{
|
||||
CLog.LogError("WiiMoteLib: Can't initialize HID API");
|
||||
const string msg = "Please install the Visual C++ Redistributable Packages 2008!";
|
||||
CLog.LogError(msg);
|
||||
CLog.LogError("Please install the Visual C++ Redistributable Packages 2008!");
|
||||
|
||||
_Active = false;
|
||||
_Error = true;
|
||||
}
|
||||
}
|
||||
|
||||
~CWiiMoteLib()
|
||||
{
|
||||
Dispose(false);
|
||||
Disconnect();
|
||||
//Wait for thread to finish (if any)
|
||||
_WaitForReader();
|
||||
CHIDApi.Exit();
|
||||
_ReadDone.Dispose();
|
||||
}
|
||||
|
||||
private bool _TryConnect(ushort pid)
|
||||
private void _StartReader()
|
||||
{
|
||||
bool connected = CHIDApi.Open(_VID, pid, out _Handle);
|
||||
if (connected)
|
||||
_Reader = new Thread(_ReaderLoop) {Name = "WiiMoteLib"};
|
||||
_Reader.Start();
|
||||
}
|
||||
|
||||
private void _WaitForReader()
|
||||
{
|
||||
if (_Reader == null)
|
||||
return;
|
||||
_Reader.Join();
|
||||
_Reader = null;
|
||||
}
|
||||
|
||||
private void _TryConnect(ushort pid)
|
||||
{
|
||||
//We might have had a reader thread, that is not finished yet, so let it finish and close it's handle first or it will close the new one
|
||||
_WaitForReader();
|
||||
Connected = CHIDApi.Open(_VID, pid, out _Handle);
|
||||
if (Connected)
|
||||
{
|
||||
connected = _ReadCalibration();
|
||||
if (!connected)
|
||||
CHIDApi.Close(_Handle);
|
||||
_StartReader();
|
||||
if (!_ReadCalibration())
|
||||
Connected = false;
|
||||
}
|
||||
return connected;
|
||||
}
|
||||
|
||||
public bool Connect()
|
||||
{
|
||||
Connected = false;
|
||||
if (Connected)
|
||||
return true;
|
||||
|
||||
if (_Error)
|
||||
return false;
|
||||
|
||||
//Try WiiMotion
|
||||
Connected = CHIDApi.Open(_VID, _PID, out _Handle);
|
||||
if (Connected)
|
||||
{
|
||||
Connected = _ReadCalibration();
|
||||
if (!Connected)
|
||||
CHIDApi.Close(_Handle);
|
||||
}
|
||||
else
|
||||
CHIDApi.Close(_Handle);
|
||||
|
||||
if (Connected)
|
||||
return true;
|
||||
|
||||
//Try WiiMotion Plus
|
||||
Connected = CHIDApi.Open(_VID, _PIDPlus, out _Handle);
|
||||
if (Connected)
|
||||
{
|
||||
Connected = _ReadCalibration();
|
||||
if (!Connected)
|
||||
CHIDApi.Close(_Handle);
|
||||
}
|
||||
else
|
||||
CHIDApi.Close(_Handle);
|
||||
_TryConnect(_PID); //Try WiiMotion
|
||||
|
||||
if (!Connected)
|
||||
_TryConnect(_PIDPlus); //Try WiiMotion Plus
|
||||
|
||||
return Connected;
|
||||
}
|
||||
@@ -264,8 +254,6 @@ namespace Vocaluxe.Lib.Input.WiiMote
|
||||
public void Disconnect()
|
||||
{
|
||||
Connected = false;
|
||||
_Active = false;
|
||||
CHIDApi.Exit();
|
||||
}
|
||||
|
||||
public void SetReportType(EInputReport type, EIRSensitivity irSensitivity, bool continuous)
|
||||
@@ -328,68 +316,54 @@ namespace Vocaluxe.Lib.Input.WiiMote
|
||||
#region Private stuff
|
||||
private void _ReaderLoop()
|
||||
{
|
||||
while (_Active)
|
||||
var buff = new byte[_ReportLength];
|
||||
while (Connected)
|
||||
{
|
||||
Thread.Sleep(5);
|
||||
|
||||
if (_Handle != IntPtr.Zero && Connected)
|
||||
int bytesRead;
|
||||
try
|
||||
{
|
||||
var buff = new byte[_ReportLength];
|
||||
|
||||
try
|
||||
bytesRead = CHIDApi.ReadTimeout(_Handle, ref buff, _ReportLength, 400);
|
||||
if (bytesRead == -1)
|
||||
{
|
||||
CHIDApi.ReadTimeout(_Handle, ref buff, _ReportLength, 200);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
CLog.LogError("(WiiMoteLib) Error reading from device: " + e);
|
||||
}
|
||||
|
||||
if (_ParseInputReport(buff))
|
||||
{
|
||||
if (WiiMoteChanged != null)
|
||||
WiiMoteChanged(this, new CWiiMoteChangedEventArgs(_WiiMoteState));
|
||||
Connected = false; //Disconnected
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
CLog.LogError("(WiiMoteLib) Error reading from device: " + e);
|
||||
Connected = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (bytesRead > 0 && _ParseInputReport(buff))
|
||||
{
|
||||
if (WiiMoteChanged != null)
|
||||
WiiMoteChanged(this, new CWiiMoteChangedEventArgs(_WiiMoteState));
|
||||
}
|
||||
Thread.Sleep(5);
|
||||
}
|
||||
CHIDApi.Close(_Handle);
|
||||
}
|
||||
|
||||
private bool _ParseInputReport(byte[] buff)
|
||||
{
|
||||
if (buff == null)
|
||||
{
|
||||
Connected = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
var type = (EInputReport)buff[0];
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case EInputReport.Buttons:
|
||||
_ParseButtons(buff);
|
||||
break;
|
||||
|
||||
case EInputReport.ButtonsAccel:
|
||||
_ParseButtons(buff);
|
||||
_ParseAccel(buff);
|
||||
break;
|
||||
|
||||
case EInputReport.IRAccel:
|
||||
_ParseButtons(buff);
|
||||
_ParseAccel(buff);
|
||||
_ParseIR(buff);
|
||||
break;
|
||||
|
||||
case EInputReport.ButtonsExtension:
|
||||
_ParseButtons(buff);
|
||||
break;
|
||||
|
||||
case EInputReport.ButtonsAccel:
|
||||
case EInputReport.ExtensionAccel:
|
||||
_ParseButtons(buff);
|
||||
_ParseAccel(buff);
|
||||
break;
|
||||
|
||||
case EInputReport.IRAccel:
|
||||
case EInputReport.IRExtensionAccel:
|
||||
_ParseButtons(buff);
|
||||
_ParseAccel(buff);
|
||||
@@ -693,24 +667,5 @@ namespace Vocaluxe.Lib.Input.WiiMote
|
||||
Thread.Sleep(100);
|
||||
}
|
||||
#endregion Private stuff
|
||||
|
||||
#region IDisposable Members
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
// ReSharper disable InconsistentNaming
|
||||
private void Dispose(bool disposing)
|
||||
// ReSharper restore InconsistentNaming
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
Disconnect();
|
||||
_ReadDone.Close();
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using Vocaluxe.Base;
|
||||
using VocaluxeLib;
|
||||
|
||||
@@ -0,0 +1,209 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Vocaluxe.Lib.Sound
|
||||
{
|
||||
class CBuffer : IDisposable
|
||||
{
|
||||
private const double _BaseToneFreq = 65.4064;
|
||||
public const int NumHalfTones = 17;
|
||||
|
||||
private const int _AnalysisBufLen = 4096;
|
||||
private const int _AnalysisByteBufLen = _AnalysisBufLen * 2;
|
||||
|
||||
private readonly Int16[] _AnalysisBuffer = new Int16[_AnalysisBufLen];
|
||||
private readonly byte[] _AnalysisByteBuffer = new byte[_AnalysisByteBufLen]; //tmp buffer (stream->tmpBuffer->(Int16)AnalysisBuffer)
|
||||
|
||||
private static readonly int[] _SamplesPerPeriodPerTone = new int[NumHalfTones]; //Precalculated table holding sample# per period for each tone
|
||||
private readonly float[] _TmpWeight = new float[NumHalfTones]; //tmp buffer for weights (gets copied to ToneWeight when checked)
|
||||
|
||||
private double _MaxVolume;
|
||||
private bool _NewSamples;
|
||||
|
||||
private MemoryStream _Stream = new MemoryStream(); // full buffer
|
||||
|
||||
public CBuffer()
|
||||
{
|
||||
ToneWeigth = new float[NumHalfTones];
|
||||
for (int i = 0; i < ToneWeigth.Length; i++)
|
||||
ToneWeigth[i] = 0.99f;
|
||||
}
|
||||
|
||||
static CBuffer()
|
||||
{
|
||||
const double halftoneBase = 1.05946309436; // 2^(1/12) -> HalftoneBase^12 = 2 (one octave)
|
||||
//Init Array to avoid costly calculations
|
||||
for (int toneIndex = 0; toneIndex < NumHalfTones; toneIndex++)
|
||||
{
|
||||
double freq = _BaseToneFreq * Math.Pow(halftoneBase, toneIndex);
|
||||
_SamplesPerPeriodPerTone[toneIndex] = (int)Math.Round(44100.0 / freq); // samples in one period
|
||||
}
|
||||
}
|
||||
|
||||
public int ToneAbs { get; private set; }
|
||||
|
||||
public int Tone { get; set; }
|
||||
|
||||
public float MaxVolume
|
||||
{
|
||||
get { return (float)_MaxVolume; }
|
||||
}
|
||||
|
||||
public bool ToneValid { get; private set; }
|
||||
|
||||
public float[] ToneWeigth { get; private set; }
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
lock (_Stream)
|
||||
{
|
||||
_Stream.SetLength(0L);
|
||||
_NewSamples = false;
|
||||
}
|
||||
ToneValid = false;
|
||||
ToneAbs = 0;
|
||||
Tone = 0;
|
||||
}
|
||||
|
||||
private void _Add(byte[] bytes)
|
||||
{
|
||||
_Stream.Write(bytes, 0, bytes.Length);
|
||||
}
|
||||
|
||||
public void ProcessNewBuffer(byte[] buffer)
|
||||
{
|
||||
// apply software boost
|
||||
//BoostBuffer(Buffer, BufferSize);
|
||||
|
||||
// voice passthrough (send data to playback-device)
|
||||
//if (assigned(fVoiceStream)) then
|
||||
//fVoiceStream.WriteData(Buffer, BufferSize);
|
||||
lock (_Stream)
|
||||
{
|
||||
_Add(buffer);
|
||||
_NewSamples = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void AnalyzeBuffer()
|
||||
{
|
||||
if (!_NewSamples)
|
||||
return;
|
||||
|
||||
lock (_Stream)
|
||||
{
|
||||
if (_Stream.Length >= _AnalysisByteBufLen)
|
||||
{
|
||||
_Stream.Position -= _AnalysisByteBufLen;
|
||||
_Stream.Read(_AnalysisByteBuffer, 0, _AnalysisByteBufLen);
|
||||
}
|
||||
_NewSamples = false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < _AnalysisBufLen; i++)
|
||||
_AnalysisBuffer[i] = BitConverter.ToInt16(_AnalysisByteBuffer, i * 2);
|
||||
|
||||
try
|
||||
{
|
||||
// find maximum volume
|
||||
_FindMaxVolume();
|
||||
|
||||
if (MaxVolume >= 0.02)
|
||||
_AnalyzeByAutocorrelation();
|
||||
else
|
||||
ToneValid = false;
|
||||
}
|
||||
catch (Exception) {}
|
||||
}
|
||||
|
||||
private void _FindMaxVolume()
|
||||
{
|
||||
short maxVolume = 0;
|
||||
for (int i = 0; i < _AnalysisBuffer.Length / 4; i++)
|
||||
{
|
||||
short volume = _AnalysisBuffer[i];
|
||||
if (volume < 0)
|
||||
{
|
||||
if (volume == Int16.MinValue)
|
||||
{
|
||||
maxVolume = Int16.MaxValue;
|
||||
break;
|
||||
}
|
||||
volume = (short)-volume;
|
||||
}
|
||||
if (volume > maxVolume)
|
||||
maxVolume = volume;
|
||||
}
|
||||
_MaxVolume = (double)maxVolume / Int16.MaxValue;
|
||||
}
|
||||
|
||||
private void _AnalyzeByAutocorrelation()
|
||||
{
|
||||
// prepare to analyze
|
||||
double maxWeight = -1.0;
|
||||
double minWeight = 1.0;
|
||||
int maxTone = -1;
|
||||
|
||||
// analyze halftones
|
||||
// Note: at the lowest tone (~65Hz) and a buffer-size of 4096
|
||||
// at 44.1 (or 48kHz) only 6 (or 5) samples are compared, this might be
|
||||
// too few samples -> use a bigger buffer-size
|
||||
for (int toneIndex = 0; toneIndex < NumHalfTones; toneIndex++)
|
||||
{
|
||||
double curWeight = _AnalyzeAutocorrelationTone(toneIndex);
|
||||
|
||||
if (curWeight > maxWeight)
|
||||
{
|
||||
maxWeight = curWeight;
|
||||
maxTone = toneIndex;
|
||||
}
|
||||
|
||||
if (curWeight < minWeight)
|
||||
minWeight = curWeight;
|
||||
|
||||
_TmpWeight[toneIndex] = (float)curWeight;
|
||||
}
|
||||
|
||||
if (maxWeight - minWeight > 0.01)
|
||||
{
|
||||
Array.Copy(_TmpWeight, ToneWeigth, NumHalfTones);
|
||||
|
||||
ToneAbs = maxTone;
|
||||
Tone = maxTone % 12;
|
||||
ToneValid = true;
|
||||
}
|
||||
else
|
||||
ToneValid = false;
|
||||
}
|
||||
|
||||
private double _AnalyzeAutocorrelationTone(int tone)
|
||||
{
|
||||
int samplesPerPeriod = _SamplesPerPeriodPerTone[tone]; // samples in one period
|
||||
|
||||
int accumDist = 0; // accumulated distances
|
||||
|
||||
// compare correlating samples
|
||||
int sampleIndex = 0; // index of sample to analyze
|
||||
// Start value= index of sample one period ahead
|
||||
for (int correlatingSampleIndex = sampleIndex + samplesPerPeriod; correlatingSampleIndex < _AnalysisBufLen; correlatingSampleIndex++, sampleIndex++)
|
||||
{
|
||||
// calc distance (correlation: 1-dist/IntMax) to corresponding sample in next period
|
||||
// distance (0=equal .. IntMax=totally different) between correlated samples
|
||||
int dist = Math.Abs(_AnalysisBuffer[sampleIndex] - _AnalysisBuffer[correlatingSampleIndex]);
|
||||
accumDist += dist;
|
||||
}
|
||||
|
||||
return 1.0 - (double)accumDist / Int16.MaxValue / _AnalysisBufLen;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_Stream != null)
|
||||
{
|
||||
_Stream.Dispose();
|
||||
_Stream = null;
|
||||
}
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
using System.Diagnostics;
|
||||
using Vocaluxe.Base;
|
||||
|
||||
namespace Vocaluxe.Lib.Sound
|
||||
{
|
||||
class CDelayTest
|
||||
{
|
||||
private struct SDelayChannel
|
||||
{
|
||||
public int Channel;
|
||||
public bool Finished;
|
||||
}
|
||||
|
||||
private const float _MaxDelayTime = 1000;
|
||||
public bool Running { get; private set; }
|
||||
private readonly Stopwatch _Timer = new Stopwatch();
|
||||
private int _Stream = -1;
|
||||
|
||||
private readonly SDelayChannel[] _DelaysChannel;
|
||||
public readonly int[] Delays;
|
||||
public readonly int NumChannels;
|
||||
|
||||
public CDelayTest(int numChannels)
|
||||
{
|
||||
NumChannels = numChannels;
|
||||
_DelaysChannel = new SDelayChannel[NumChannels];
|
||||
Delays = new int[NumChannels];
|
||||
}
|
||||
|
||||
public void Start(int[] channels)
|
||||
{
|
||||
if (Running)
|
||||
return;
|
||||
Reset();
|
||||
for (int i = 0; i < _DelaysChannel.Length; i++)
|
||||
{
|
||||
if (i < channels.Length)
|
||||
{
|
||||
_DelaysChannel[i].Finished = false;
|
||||
_DelaysChannel[i].Channel = channels[i];
|
||||
}
|
||||
else
|
||||
_DelaysChannel[i].Finished = true;
|
||||
}
|
||||
_Stream = CSound.PlaySound(ESounds.T440, false);
|
||||
Running = true;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
Running = false;
|
||||
for (int i = 0; i < _DelaysChannel.Length; i++)
|
||||
Delays[i] = 0;
|
||||
_CloseStream();
|
||||
}
|
||||
|
||||
private void _CloseStream()
|
||||
{
|
||||
if (_Stream != -1)
|
||||
{
|
||||
CSound.Close(_Stream);
|
||||
_Stream = -1;
|
||||
}
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
if (!Running)
|
||||
return;
|
||||
if (!_Timer.IsRunning)
|
||||
{
|
||||
if (CSound.GetPosition(_Stream) > 0f)
|
||||
_Timer.Restart();
|
||||
}
|
||||
if (!_Timer.IsRunning)
|
||||
return;
|
||||
|
||||
bool isActive = false;
|
||||
if (_Timer.ElapsedMilliseconds <= _MaxDelayTime)
|
||||
{
|
||||
for (int i = 0; i < _DelaysChannel.Length; i++)
|
||||
{
|
||||
if (_DelaysChannel[i].Channel < 0 || _DelaysChannel[i].Finished)
|
||||
continue;
|
||||
if (CSound.RecordGetMaxVolume(_DelaysChannel[i].Channel) > 0.1f && CSound.RecordGetTone(_DelaysChannel[i].Channel) == 9)
|
||||
{
|
||||
Delays[i] = (int)_Timer.ElapsedMilliseconds;
|
||||
_DelaysChannel[i].Finished = true;
|
||||
}
|
||||
else
|
||||
isActive = true;
|
||||
}
|
||||
}
|
||||
if (!isActive)
|
||||
{
|
||||
Running = false;
|
||||
_CloseStream();
|
||||
_Timer.Stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -192,7 +192,7 @@ namespace Vocaluxe.Lib.Sound
|
||||
if (!_Initialized)
|
||||
return 0;
|
||||
|
||||
return _Buffer[player].NumHalfTones;
|
||||
return CBuffer.NumHalfTones;
|
||||
}
|
||||
|
||||
public float[] ToneWeigth(int player)
|
||||
@@ -326,7 +326,7 @@ namespace Vocaluxe.Lib.Sound
|
||||
for (int i = 0; i < _Notifications.Count; i++)
|
||||
_WaitHandles[i] = _Notifications[i].Event;
|
||||
|
||||
_CaptureThread = new Thread(_DoCapture) {IsBackground = true};
|
||||
_CaptureThread = new Thread(_DoCapture) {Name = "DirectSoundCapture", IsBackground = true};
|
||||
|
||||
_Running = true;
|
||||
_CaptureThread.Start();
|
||||
|
||||
@@ -20,8 +20,8 @@ using System.Collections.Generic;
|
||||
using Gst;
|
||||
using GLib;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Diagnostics;
|
||||
using Vocaluxe.Base;
|
||||
using VocaluxeLib;
|
||||
using Thread = System.Threading.Thread;
|
||||
|
||||
namespace Vocaluxe.Lib.Sound
|
||||
@@ -37,10 +37,10 @@ namespace Vocaluxe.Lib.Sound
|
||||
public bool Init()
|
||||
{
|
||||
#if ARCH_X86
|
||||
string path = ".\\x86\\gstreamer";
|
||||
const string path = ".\\x86\\gstreamer";
|
||||
#endif
|
||||
#if ARCH_X64
|
||||
string path = ".\\x64\\gstreamer";
|
||||
const string path = ".\\x64\\gstreamer";
|
||||
#endif
|
||||
SetDllDirectory(path);
|
||||
Application.Init();
|
||||
@@ -213,21 +213,16 @@ namespace Vocaluxe.Lib.Sound
|
||||
|
||||
private class CGstreamerSharpAudioStream
|
||||
{
|
||||
private readonly Element _Element;
|
||||
private Element _Element;
|
||||
private bool _Loop;
|
||||
public volatile bool Closed;
|
||||
public volatile bool Closed = true;
|
||||
public volatile bool Finished;
|
||||
|
||||
private bool _Fading;
|
||||
private bool _CloseStreamAfterFade;
|
||||
private bool _PauseStreamAfterFade;
|
||||
private bool _StopStreamAfterFade;
|
||||
private readonly Stopwatch _FadeTimer = new Stopwatch();
|
||||
private float _FadeTime;
|
||||
private float _FadeVolume;
|
||||
private float _Volume = 100f;
|
||||
private CFading _Fading;
|
||||
private EStreamAction _AfterFadeAction;
|
||||
private float _Volume = 1f;
|
||||
|
||||
private float _MaxVolume = 100f;
|
||||
private float _MaxVolume = 1f;
|
||||
|
||||
private volatile float _Duration = -1f;
|
||||
private volatile float _Position;
|
||||
@@ -240,7 +235,10 @@ namespace Vocaluxe.Lib.Sound
|
||||
var audioSinkBin = new Bin("Audiosink");
|
||||
|
||||
if (convert == null || audiosink == null)
|
||||
{
|
||||
CLog.LogError("Could not create pipeline");
|
||||
return;
|
||||
}
|
||||
|
||||
audioSinkBin.Add(convert);
|
||||
audioSinkBin.Add(audiosink);
|
||||
@@ -249,21 +247,35 @@ namespace Vocaluxe.Lib.Sound
|
||||
GhostPad ghostpad = new GhostPad("sink", pad);
|
||||
|
||||
if (pad == null)
|
||||
{
|
||||
CLog.LogError("Could not create pads");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ghostpad.SetActive(true))
|
||||
{
|
||||
CLog.LogError("Could not link pads");
|
||||
return;
|
||||
}
|
||||
if (!audioSinkBin.AddPad(ghostpad))
|
||||
{
|
||||
CLog.LogError("Could not add pad");
|
||||
return;
|
||||
}
|
||||
|
||||
_Element = ElementFactory.Make("playbin", "playbin");
|
||||
if (_Element == null)
|
||||
{
|
||||
CLog.LogError("Could not create playbin");
|
||||
return;
|
||||
}
|
||||
_Element["audio-sink"] = audioSinkBin;
|
||||
_Element["flags"] = 1 << 1;
|
||||
_Element["uri"] = new Uri(media).AbsoluteUri;
|
||||
_Element.SetState(State.Paused);
|
||||
|
||||
Closed = false; //Enable stream
|
||||
|
||||
// Passing CLOCK_TIME_NONE here causes the pipeline to block for a long time so with
|
||||
// prescan enabled the pipeline will wait 500ms for stream to initialize and then continue
|
||||
// if it takes more than 500ms, duration queries will be performed asynchronously
|
||||
@@ -285,8 +297,10 @@ namespace Vocaluxe.Lib.Sound
|
||||
if (_Loop)
|
||||
Position = 0;
|
||||
else
|
||||
{
|
||||
Finished = true;
|
||||
Close();
|
||||
Close();
|
||||
}
|
||||
break;
|
||||
case MessageType.Error:
|
||||
GException error;
|
||||
@@ -295,7 +309,8 @@ namespace Vocaluxe.Lib.Sound
|
||||
CLog.LogError("Gstreamer error: message" + error.Message + ", code" + error.Code + " ,debug information" + debug);
|
||||
break;
|
||||
case MessageType.DurationChanged:
|
||||
_UpdateDuration();
|
||||
if (!_QueryingDuration)
|
||||
_UpdateDuration();
|
||||
break;
|
||||
}
|
||||
msg.Unref();
|
||||
@@ -307,7 +322,7 @@ namespace Vocaluxe.Lib.Sound
|
||||
{
|
||||
Closed = true;
|
||||
Finished = true;
|
||||
var t = new Thread(_TerminateStream);
|
||||
var t = new Thread(_TerminateStream) {Name = "GSt Terminate"};
|
||||
t.Start();
|
||||
}
|
||||
}
|
||||
@@ -318,6 +333,7 @@ namespace Vocaluxe.Lib.Sound
|
||||
{
|
||||
_Element.SetState(State.Null);
|
||||
_Element.Dispose();
|
||||
_Element = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -337,47 +353,45 @@ namespace Vocaluxe.Lib.Sound
|
||||
|
||||
public void Fade(float targetVolume, float seconds)
|
||||
{
|
||||
_Fading = true;
|
||||
_FadeTimer.Restart();
|
||||
_FadeTime = seconds;
|
||||
_FadeVolume = targetVolume;
|
||||
_Fading = new CFading(_Volume, targetVolume, seconds);
|
||||
_AfterFadeAction = EStreamAction.Nothing;
|
||||
}
|
||||
|
||||
public void FadeAndPause(float targetVolume, float seconds)
|
||||
{
|
||||
Fade(targetVolume, seconds);
|
||||
_PauseStreamAfterFade = true;
|
||||
_AfterFadeAction = EStreamAction.Pause;
|
||||
}
|
||||
|
||||
public void FadeAndClose(float targetVolume, float seconds)
|
||||
{
|
||||
Fade(targetVolume, seconds);
|
||||
_CloseStreamAfterFade = true;
|
||||
_AfterFadeAction = EStreamAction.Close;
|
||||
}
|
||||
|
||||
public void FadeAndStop(float targetVolume, float seconds)
|
||||
{
|
||||
Fade(targetVolume, seconds);
|
||||
_StopStreamAfterFade = true;
|
||||
_AfterFadeAction = EStreamAction.Stop;
|
||||
}
|
||||
|
||||
public float Volume
|
||||
{
|
||||
get { return _Element != null ? (float)(double)_Element["volume"] : 0; }
|
||||
get { return _Volume * 100f; }
|
||||
set
|
||||
{
|
||||
_Volume = value;
|
||||
_Volume = value / 100f;
|
||||
if (_Element != null)
|
||||
_Element["volume"] = ((value / 100d) * (_MaxVolume / 100d));
|
||||
_Element["volume"] = (_Volume * _MaxVolume);
|
||||
}
|
||||
}
|
||||
|
||||
public float MaxVolume
|
||||
{
|
||||
get { return _MaxVolume; }
|
||||
get { return _MaxVolume * 100f; }
|
||||
set
|
||||
{
|
||||
_MaxVolume = value;
|
||||
_MaxVolume = value / 100f;
|
||||
Volume = _Volume;
|
||||
}
|
||||
}
|
||||
@@ -388,7 +402,8 @@ namespace Vocaluxe.Lib.Sound
|
||||
{
|
||||
if (_Duration < 0 && !_QueryingDuration)
|
||||
{
|
||||
var t = new Thread(_UpdateDuration);
|
||||
_QueryingDuration = true; // Set this to avoid race conditions
|
||||
var t = new Thread(_UpdateDuration) {Name = "GSt Update Duration"};
|
||||
t.Start();
|
||||
}
|
||||
return _Duration > 0 ? _Duration : -1;
|
||||
@@ -438,25 +453,25 @@ namespace Vocaluxe.Lib.Sound
|
||||
while (_Element != null && _Element.Bus != null && _Element.Bus.HavePending())
|
||||
_OnMessage(_Element.Bus.Pop());
|
||||
|
||||
if (_Fading)
|
||||
if (_Fading != null)
|
||||
{
|
||||
if (_FadeTimer.ElapsedMilliseconds < (_FadeTime * 1000f))
|
||||
Volume = ((_FadeTimer.ElapsedMilliseconds) / (_FadeTime * 1000f)) * _FadeVolume;
|
||||
else
|
||||
bool finished;
|
||||
Volume = _Fading.GetValue(out finished);
|
||||
if (finished)
|
||||
{
|
||||
Volume = _FadeVolume;
|
||||
if (_CloseStreamAfterFade)
|
||||
Close();
|
||||
if (_PauseStreamAfterFade)
|
||||
Paused = true;
|
||||
if (_StopStreamAfterFade)
|
||||
Stop();
|
||||
|
||||
_CloseStreamAfterFade = false;
|
||||
_PauseStreamAfterFade = false;
|
||||
_StopStreamAfterFade = false;
|
||||
_Fading = false;
|
||||
_FadeTimer.Reset();
|
||||
switch (_AfterFadeAction)
|
||||
{
|
||||
case EStreamAction.Pause:
|
||||
Paused = true;
|
||||
break;
|
||||
case EStreamAction.Stop:
|
||||
Stop();
|
||||
break;
|
||||
case EStreamAction.Close:
|
||||
Close();
|
||||
break;
|
||||
}
|
||||
_Fading = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ using System.IO;
|
||||
using System.Threading;
|
||||
using Vocaluxe.Base;
|
||||
using Vocaluxe.Lib.Sound.Decoder;
|
||||
using VocaluxeLib;
|
||||
|
||||
namespace Vocaluxe.Lib.Sound
|
||||
{
|
||||
@@ -370,14 +371,8 @@ namespace Vocaluxe.Lib.Sound
|
||||
private float _Volume = 1f;
|
||||
private float _VolumeMax = 1f;
|
||||
|
||||
private readonly Stopwatch _FadeTimer = new Stopwatch();
|
||||
|
||||
private float _FadeTime;
|
||||
private float _TargetVolume = 1f;
|
||||
private float _StartVolume = 1f;
|
||||
private bool _CloseStreamAfterFade;
|
||||
private bool _PauseStreamAfterFade;
|
||||
private bool _Fading;
|
||||
private EStreamAction _AfterFadeAction;
|
||||
private CFading _Fading;
|
||||
|
||||
private readonly Stopwatch _Timer = new Stopwatch();
|
||||
|
||||
@@ -416,7 +411,7 @@ namespace Vocaluxe.Lib.Sound
|
||||
public COpenAlStream()
|
||||
{
|
||||
_Initialized = false;
|
||||
_DecoderThread = new Thread(_Execute);
|
||||
_DecoderThread = new Thread(_Execute) {Name = "OpenAL Decode"};
|
||||
}
|
||||
|
||||
public void Free(Closeproc closeProc, int streamID, Object closeMutex)
|
||||
@@ -519,33 +514,28 @@ namespace Vocaluxe.Lib.Sound
|
||||
|
||||
public void Fade(float targetVolume, float fadeTime)
|
||||
{
|
||||
_Fading = true;
|
||||
_FadeTimer.Stop();
|
||||
_FadeTimer.Reset();
|
||||
_StartVolume = _Volume;
|
||||
_TargetVolume = targetVolume / 100f;
|
||||
_FadeTime = fadeTime;
|
||||
_FadeTimer.Start();
|
||||
_Fading = new CFading(_Volume, targetVolume, fadeTime);
|
||||
_AfterFadeAction = EStreamAction.Nothing;
|
||||
}
|
||||
|
||||
public void FadeAndPause(float targetVolume, float fadeTime)
|
||||
{
|
||||
_PauseStreamAfterFade = true;
|
||||
Fade(targetVolume, fadeTime);
|
||||
_AfterFadeAction = EStreamAction.Pause;
|
||||
}
|
||||
|
||||
public void FadeAndStop(float targetVolume, float fadeTime, Closeproc closeProc, int streamID)
|
||||
{
|
||||
_Closeproc = closeProc;
|
||||
_StreamID = streamID;
|
||||
_CloseStreamAfterFade = true;
|
||||
Fade(targetVolume, fadeTime);
|
||||
_AfterFadeAction = EStreamAction.Stop;
|
||||
}
|
||||
|
||||
public void Play()
|
||||
{
|
||||
Paused = false;
|
||||
_PauseStreamAfterFade = false;
|
||||
_AfterFadeAction = EStreamAction.Nothing;
|
||||
AL.SourcePlay(_Source);
|
||||
}
|
||||
|
||||
@@ -745,21 +735,23 @@ namespace Vocaluxe.Lib.Sound
|
||||
|
||||
private void _Update()
|
||||
{
|
||||
if (_Fading)
|
||||
if (_Fading != null)
|
||||
{
|
||||
if (_FadeTimer.ElapsedMilliseconds / 1000f < _FadeTime)
|
||||
_Volume = _StartVolume + (_TargetVolume - _StartVolume) * ((_FadeTimer.ElapsedMilliseconds / 1000f) / _FadeTime);
|
||||
else
|
||||
bool finished;
|
||||
_Volume = _Fading.GetValue(out finished);
|
||||
if (finished)
|
||||
{
|
||||
_Volume = _TargetVolume;
|
||||
_FadeTimer.Stop();
|
||||
_Fading = false;
|
||||
|
||||
if (_CloseStreamAfterFade)
|
||||
_Terminated = true;
|
||||
|
||||
if (_PauseStreamAfterFade)
|
||||
Paused = true;
|
||||
switch (_AfterFadeAction)
|
||||
{
|
||||
case EStreamAction.Close:
|
||||
case EStreamAction.Stop:
|
||||
_Terminated = true;
|
||||
break;
|
||||
case EStreamAction.Pause:
|
||||
Paused = true;
|
||||
break;
|
||||
}
|
||||
_Fading = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
@@ -25,6 +24,7 @@ using System.Threading;
|
||||
using Vocaluxe.Base;
|
||||
using Vocaluxe.Lib.Sound.Decoder;
|
||||
using Vocaluxe.Lib.Sound.PortAudio;
|
||||
using VocaluxeLib;
|
||||
|
||||
namespace Vocaluxe.Lib.Sound
|
||||
{
|
||||
@@ -351,15 +351,8 @@ namespace Vocaluxe.Lib.Sound
|
||||
private float _Volume = 1f;
|
||||
private float _VolumeMax = 1f;
|
||||
|
||||
private readonly Stopwatch _FadeTimer = new Stopwatch();
|
||||
|
||||
private float _FadeTime;
|
||||
private float _TargetVolume = 1f;
|
||||
private float _StartVolume = 1f;
|
||||
private bool _CloseStreamAfterFade;
|
||||
private bool _PauseStreamAfterFade;
|
||||
private bool _StopStreamAfterFade;
|
||||
private bool _Fading;
|
||||
private EStreamAction _AfterFadeAction;
|
||||
private CFading _Fading;
|
||||
|
||||
private static CPortAudio.SPaHostApiInfo _ApiInfo;
|
||||
private static CPortAudio.SPaDeviceInfo _OutputDeviceInfo;
|
||||
@@ -401,7 +394,7 @@ namespace Vocaluxe.Lib.Sound
|
||||
public CPortAudioStream()
|
||||
{
|
||||
_SyncTimer = new CSyncTimer(0f, 1f, 0.02f);
|
||||
_DecoderThread = new Thread(_Execute);
|
||||
_DecoderThread = new Thread(_Execute) {Name = "PortAudio Decode"};
|
||||
}
|
||||
|
||||
~CPortAudioStream()
|
||||
@@ -507,19 +500,12 @@ namespace Vocaluxe.Lib.Sound
|
||||
|
||||
public void Fade(float targetVolume, float fadeTime)
|
||||
{
|
||||
_Fading = true;
|
||||
_FadeTimer.Stop();
|
||||
_FadeTimer.Reset();
|
||||
_StartVolume = _Volume;
|
||||
_TargetVolume = targetVolume / 100f;
|
||||
_FadeTime = fadeTime;
|
||||
_FadeTimer.Start();
|
||||
_Fading = new CFading(_Volume, targetVolume, fadeTime);
|
||||
_AfterFadeAction = EStreamAction.Nothing;
|
||||
}
|
||||
|
||||
public void FadeAndPause(float targetVolume, float fadeTime)
|
||||
{
|
||||
_PauseStreamAfterFade = true;
|
||||
|
||||
Fade(targetVolume, fadeTime);
|
||||
}
|
||||
|
||||
@@ -527,25 +513,22 @@ namespace Vocaluxe.Lib.Sound
|
||||
{
|
||||
_Closeproc = closeProc;
|
||||
_StreamID = streamID;
|
||||
_CloseStreamAfterFade = true;
|
||||
|
||||
Fade(targetVolume, fadeTime);
|
||||
_AfterFadeAction = EStreamAction.Close;
|
||||
}
|
||||
|
||||
public void FadeAndStop(float targetVolume, float fadeTime, Closeproc closeProc, int streamID)
|
||||
{
|
||||
_Closeproc = closeProc;
|
||||
_StreamID = streamID;
|
||||
_StopStreamAfterFade = true;
|
||||
|
||||
Fade(targetVolume, fadeTime);
|
||||
_AfterFadeAction = EStreamAction.Stop;
|
||||
}
|
||||
|
||||
public void Play()
|
||||
{
|
||||
Paused = false;
|
||||
_PauseStreamAfterFade = false;
|
||||
_StopStreamAfterFade = false;
|
||||
_AfterFadeAction = EStreamAction.Nothing;
|
||||
lock (_Mutex)
|
||||
{
|
||||
_ErrorCheck("StartStream", CPortAudio.Pa_StartStream(_Ptr));
|
||||
@@ -665,7 +648,7 @@ namespace Vocaluxe.Lib.Sound
|
||||
return -1;
|
||||
}
|
||||
|
||||
public bool Skip(float time)
|
||||
public void Skip(float time)
|
||||
{
|
||||
lock (_LockSyncSignals)
|
||||
{
|
||||
@@ -673,8 +656,6 @@ namespace Vocaluxe.Lib.Sound
|
||||
_SetSkip = true;
|
||||
_Waiting = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#region Threading
|
||||
@@ -929,23 +910,25 @@ namespace Vocaluxe.Lib.Sound
|
||||
|
||||
private void _Update()
|
||||
{
|
||||
if (_Fading)
|
||||
if (_Fading != null)
|
||||
{
|
||||
if (_FadeTimer.ElapsedMilliseconds / 1000f < _FadeTime)
|
||||
_Volume = _StartVolume + (_TargetVolume - _StartVolume) * ((_FadeTimer.ElapsedMilliseconds / 1000f) / _FadeTime);
|
||||
else
|
||||
bool finished;
|
||||
_Volume = _Fading.GetValue(out finished);
|
||||
if (finished)
|
||||
{
|
||||
_Volume = _TargetVolume;
|
||||
_FadeTimer.Stop();
|
||||
_Fading = false;
|
||||
|
||||
if (_CloseStreamAfterFade)
|
||||
_Terminated = true;
|
||||
|
||||
if (_PauseStreamAfterFade)
|
||||
Paused = true;
|
||||
if (_StopStreamAfterFade)
|
||||
Stop();
|
||||
switch (_AfterFadeAction)
|
||||
{
|
||||
case EStreamAction.Close:
|
||||
_Terminated = true;
|
||||
break;
|
||||
case EStreamAction.Stop:
|
||||
Stop();
|
||||
break;
|
||||
case EStreamAction.Pause:
|
||||
Paused = true;
|
||||
break;
|
||||
}
|
||||
_Fading = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -246,7 +246,7 @@ namespace Vocaluxe.Lib.Sound
|
||||
if (!_Initialized)
|
||||
return 0;
|
||||
|
||||
return _Buffer[player].NumHalfTones;
|
||||
return CBuffer.NumHalfTones;
|
||||
}
|
||||
|
||||
public float[] ToneWeigth(int player)
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Vocaluxe.Lib.Sound
|
||||
{
|
||||
class CPt1
|
||||
{
|
||||
private float _CurrentTime;
|
||||
private float _OldTime;
|
||||
|
||||
private readonly Stopwatch _Timer;
|
||||
private readonly float _K;
|
||||
private readonly float _T;
|
||||
|
||||
public float Time
|
||||
{
|
||||
get
|
||||
{
|
||||
double nanosecPerTick = (1000.0 * 1000.0 * 1000.0) / Stopwatch.Frequency;
|
||||
long ticks = _Timer.ElapsedTicks;
|
||||
float dt = _Timer.ElapsedMilliseconds / 1000f;
|
||||
|
||||
if (Stopwatch.IsHighResolution && ticks != 0)
|
||||
dt = (float)(ticks * nanosecPerTick / 1000000000.0);
|
||||
|
||||
return _CurrentTime + dt;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (value < 0f)
|
||||
return;
|
||||
|
||||
_CurrentTime = value;
|
||||
_OldTime = value;
|
||||
_Timer.Reset();
|
||||
_Timer.Start();
|
||||
}
|
||||
}
|
||||
|
||||
public CPt1(float currentTime, float k, float t)
|
||||
{
|
||||
_CurrentTime = currentTime;
|
||||
_OldTime = currentTime;
|
||||
|
||||
_Timer = new Stopwatch();
|
||||
_K = k;
|
||||
_T = t;
|
||||
}
|
||||
|
||||
public float Update(float newTime)
|
||||
{
|
||||
_Timer.Stop();
|
||||
|
||||
double nanosecPerTick = (1000.0 * 1000.0 * 1000.0) / Stopwatch.Frequency;
|
||||
long ticks = _Timer.ElapsedTicks;
|
||||
float dt = _Timer.ElapsedMilliseconds / 1000f;
|
||||
|
||||
if (Stopwatch.IsHighResolution && ticks != 0)
|
||||
dt = (float)(ticks * nanosecPerTick / 1000000000.0);
|
||||
|
||||
float ts = 0f;
|
||||
if (dt > 0)
|
||||
ts = 1 / (_T / dt + 1);
|
||||
|
||||
_CurrentTime = ts * (_K * newTime - _OldTime) + _OldTime;
|
||||
_OldTime = _CurrentTime;
|
||||
|
||||
_Timer.Restart();
|
||||
|
||||
return _CurrentTime;
|
||||
}
|
||||
|
||||
public void Pause()
|
||||
{
|
||||
_Timer.Stop();
|
||||
}
|
||||
|
||||
public void Resume()
|
||||
{
|
||||
_Timer.Start();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Vocaluxe.Lib.Sound
|
||||
{
|
||||
class CSyncTimer
|
||||
{
|
||||
private readonly CPt1 _ExternTime;
|
||||
private readonly Stopwatch _Timer;
|
||||
private float _SetValue;
|
||||
|
||||
public float Time
|
||||
{
|
||||
get
|
||||
{
|
||||
double nanosecPerTick = (1000.0 * 1000.0 * 1000.0) / Stopwatch.Frequency;
|
||||
long ticks = _Timer.ElapsedTicks;
|
||||
float dt = _Timer.ElapsedMilliseconds / 1000f;
|
||||
|
||||
if (Stopwatch.IsHighResolution && ticks != 0)
|
||||
dt = (float)(ticks * nanosecPerTick / 1000000000.0);
|
||||
|
||||
return _SetValue + dt;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
_ExternTime.Time = value;
|
||||
_SetValue = value;
|
||||
_Timer.Reset();
|
||||
_Timer.Start();
|
||||
}
|
||||
}
|
||||
|
||||
public CSyncTimer(float currentTime, float k, float t)
|
||||
{
|
||||
_ExternTime = new CPt1(currentTime, k, t);
|
||||
_Timer = new Stopwatch();
|
||||
_SetValue = currentTime;
|
||||
}
|
||||
|
||||
public float Update(float newTime)
|
||||
{
|
||||
float et = _ExternTime.Update(newTime);
|
||||
|
||||
float dt = Time;
|
||||
|
||||
float diff = et - dt;
|
||||
if (Math.Abs(diff) > 0.05f)
|
||||
{
|
||||
_Timer.Reset();
|
||||
_Timer.Start();
|
||||
_SetValue = dt + diff;
|
||||
dt = _SetValue;
|
||||
//Console.WriteLine("DRIFTED!!! " + diff.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (diff > 0.01f)
|
||||
_SetValue += 0.000025f;
|
||||
|
||||
if (diff < -0.01f)
|
||||
_SetValue -= 0.000025f;
|
||||
}
|
||||
//Console.WriteLine(diff.ToString());
|
||||
return dt;
|
||||
}
|
||||
|
||||
public void Pause()
|
||||
{
|
||||
_ExternTime.Pause();
|
||||
_Timer.Stop();
|
||||
}
|
||||
|
||||
public void Resume()
|
||||
{
|
||||
_ExternTime.Resume();
|
||||
_Timer.Start();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,14 @@
|
||||
|
||||
namespace Vocaluxe.Lib.Sound
|
||||
{
|
||||
public enum EStreamAction
|
||||
{
|
||||
Nothing,
|
||||
Pause,
|
||||
Stop,
|
||||
Close
|
||||
}
|
||||
|
||||
struct SAudioStreams
|
||||
{
|
||||
public int Handle;
|
||||
|
||||
@@ -18,432 +18,132 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using Vocaluxe.Base;
|
||||
using VocaluxeLib.Draw;
|
||||
|
||||
namespace Vocaluxe.Lib.Video.Acinerella
|
||||
{
|
||||
class CDecoder
|
||||
{
|
||||
private IntPtr _Instance = IntPtr.Zero; // acinerella instance
|
||||
private IntPtr _Videodecoder = IntPtr.Zero; // acinerella video decoder instance
|
||||
|
||||
private readonly Stopwatch _LoopTimer = new Stopwatch();
|
||||
private readonly Thread _Thread;
|
||||
private readonly Object _MutexFramebuffer = new Object();
|
||||
private readonly CFramebuffer _Framebuffer;
|
||||
private readonly Object _MutexSyncSignals = new Object();
|
||||
|
||||
private bool _FileOpened;
|
||||
|
||||
private float _FrameDuration; // frame time in s
|
||||
private float _LastDecodedTime; // time of last decoded frame
|
||||
private float _LastShownTime; // time if the last shown frame in s
|
||||
|
||||
private float _Time;
|
||||
private float _Gap;
|
||||
private float _Start;
|
||||
private bool _Loop;
|
||||
|
||||
private float _SetTime;
|
||||
private float _SetGap;
|
||||
private float _SetStart;
|
||||
private bool _SetSkip;
|
||||
|
||||
private bool _Terminated;
|
||||
private bool _FrameAvailable;
|
||||
private bool _NoMoreFrames;
|
||||
private readonly AutoResetEvent _EvWakeUp = new AutoResetEvent(false);
|
||||
private bool _IsSleeping;
|
||||
private int _WaitCount;
|
||||
|
||||
private float _SkipTime; // = Start + VideoGap
|
||||
|
||||
private string _FileName; // current video file name
|
||||
private int _Width;
|
||||
private int _Height;
|
||||
private bool _Paused;
|
||||
private float _LoopTime;
|
||||
|
||||
private CDecoderThread _Thread;
|
||||
public float Length { get; private set; }
|
||||
public bool Finished { get; private set; }
|
||||
|
||||
public CDecoder()
|
||||
{
|
||||
_Thread = new Thread(_Execute);
|
||||
_Framebuffer = new CFramebuffer(10);
|
||||
Length = 0;
|
||||
Finished = true;
|
||||
}
|
||||
|
||||
public float Length { get; private set; }
|
||||
public bool Loop
|
||||
{
|
||||
get { return _Thread.Loop; }
|
||||
set
|
||||
{
|
||||
{
|
||||
_Thread.Loop = value;
|
||||
if (value)
|
||||
{
|
||||
_LoopTime = _Thread.RequestTime;
|
||||
_LoopTimer.Restart();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool Paused
|
||||
{
|
||||
set
|
||||
{
|
||||
lock (_MutexSyncSignals)
|
||||
if (_Paused == value)
|
||||
return;
|
||||
_Paused = value;
|
||||
if (_Paused)
|
||||
{
|
||||
_Paused = value;
|
||||
if (_Paused)
|
||||
_LoopTimer.Stop();
|
||||
else
|
||||
_LoopTimer.Start();
|
||||
_LoopTimer.Stop();
|
||||
_Thread.Pause();
|
||||
}
|
||||
else
|
||||
{
|
||||
_LoopTimer.Start();
|
||||
_Thread.Resume();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool Loop { private get; set; }
|
||||
|
||||
public bool Finished { get; private set; }
|
||||
|
||||
public bool Open(string fileName)
|
||||
{
|
||||
if (_FileOpened)
|
||||
if (_Thread != null)
|
||||
return false;
|
||||
|
||||
if (!File.Exists(fileName))
|
||||
return false;
|
||||
|
||||
_FileName = fileName;
|
||||
|
||||
//Do this here as one may want to get the length afterwards!
|
||||
if (!_DoOpen())
|
||||
return false;
|
||||
|
||||
_FileOpened = true;
|
||||
|
||||
_Thread.Priority = ThreadPriority.Normal;
|
||||
_Thread.Name = Path.GetFileName(fileName);
|
||||
_Thread.Start();
|
||||
return true;
|
||||
_Thread = new CDecoderThread();
|
||||
if (_Thread.LoadFile(fileName))
|
||||
{
|
||||
Length = _Thread.Length;
|
||||
Finished = false;
|
||||
return _Thread.Start();
|
||||
}
|
||||
_Thread = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
_Terminated = true;
|
||||
if (_Thread != null)
|
||||
_Thread.Stop();
|
||||
Length = 0;
|
||||
Finished = true;
|
||||
}
|
||||
|
||||
public bool GetFrame(ref CTexture frame, float time, out float videoTime)
|
||||
{
|
||||
if (Finished)
|
||||
{
|
||||
videoTime = Length - _Gap;
|
||||
return false;
|
||||
}
|
||||
if (Loop)
|
||||
{
|
||||
lock (_MutexSyncSignals)
|
||||
time = _LoopTime + _LoopTimer.ElapsedMilliseconds / 1000f;
|
||||
if (time >= Length)
|
||||
{
|
||||
_SetTime += _LoopTimer.ElapsedMilliseconds / 1000f;
|
||||
do
|
||||
{
|
||||
time -= Length;
|
||||
} while (time >= Length);
|
||||
_LoopTime = time;
|
||||
_LoopTimer.Restart();
|
||||
}
|
||||
}
|
||||
else if (Math.Abs(_SetTime - time) >= 1f / 1000f) //Check 1 ms difference
|
||||
{
|
||||
lock (_MutexSyncSignals)
|
||||
{
|
||||
_SetTime = time;
|
||||
}
|
||||
}
|
||||
else if (Math.Abs(_LastShownTime - time) < 1f / 1000 && frame != null) //Check 1 ms difference
|
||||
{
|
||||
videoTime = _LastShownTime;
|
||||
return true;
|
||||
}
|
||||
_UploadNewFrame(ref frame);
|
||||
videoTime = _LastShownTime;
|
||||
else
|
||||
time += _Gap;
|
||||
_Thread.SyncTime(time);
|
||||
|
||||
bool finished;
|
||||
_Thread.GetFrame(ref frame, ref time, out finished);
|
||||
videoTime = time - _Gap;
|
||||
|
||||
if (finished) //Only set, not reset
|
||||
Finished = true;
|
||||
return frame != null;
|
||||
}
|
||||
|
||||
public bool Skip(float start, float gap)
|
||||
{
|
||||
lock (_MutexSyncSignals)
|
||||
{
|
||||
_SetStart = start;
|
||||
_SetGap = gap;
|
||||
_SetSkip = true;
|
||||
_NoMoreFrames = false;
|
||||
Finished = false;
|
||||
}
|
||||
Finished = false;
|
||||
_Gap = gap;
|
||||
_Thread.Skip(start + gap);
|
||||
if (Loop)
|
||||
Loop = true; //Reset loop (timer)
|
||||
return true;
|
||||
}
|
||||
|
||||
#region Threading
|
||||
private void _Skip()
|
||||
{
|
||||
_SkipTime = _Start + _Gap;
|
||||
|
||||
if (_SkipTime < 0)
|
||||
_SkipTime = 0;
|
||||
|
||||
try
|
||||
{
|
||||
CAcinerella.AcSeek(_Videodecoder, -1, (Int64)(_SkipTime * 1000f));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
CLog.LogError("Error seeking video file \"" + _FileName + "\": " + e.Message);
|
||||
}
|
||||
_LastDecodedTime = _SkipTime;
|
||||
|
||||
lock (_MutexFramebuffer)
|
||||
{
|
||||
_Framebuffer.Clear();
|
||||
}
|
||||
|
||||
_FrameAvailable = false;
|
||||
}
|
||||
|
||||
private void _Execute()
|
||||
{
|
||||
while (!_Terminated)
|
||||
{
|
||||
bool skip;
|
||||
lock (_MutexSyncSignals)
|
||||
{
|
||||
_Time = _SetTime;
|
||||
skip = _SetSkip;
|
||||
_SetSkip = false;
|
||||
_Gap = _SetGap;
|
||||
_Start = _SetStart;
|
||||
_Loop = Loop;
|
||||
}
|
||||
|
||||
if (skip)
|
||||
_Skip();
|
||||
|
||||
if (!_FrameAvailable)
|
||||
_Decode();
|
||||
|
||||
if (_FrameAvailable)
|
||||
{
|
||||
if (!_Framebuffer.IsFull())
|
||||
{
|
||||
_Copy();
|
||||
_WaitCount = 0;
|
||||
Thread.Sleep(1);
|
||||
}
|
||||
else if (_WaitCount > 3)
|
||||
{
|
||||
_IsSleeping = true;
|
||||
_EvWakeUp.WaitOne();
|
||||
}
|
||||
else
|
||||
{
|
||||
Thread.Sleep((int)((_Framebuffer.Size - 2) * _FrameDuration * 1000));
|
||||
_WaitCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_Free();
|
||||
}
|
||||
|
||||
private bool _DoOpen()
|
||||
{
|
||||
bool ok;
|
||||
try
|
||||
{
|
||||
_Instance = CAcinerella.AcInit();
|
||||
CAcinerella.AcOpen2(_Instance, _FileName);
|
||||
|
||||
var instance = (SACInstance)Marshal.PtrToStructure(_Instance, typeof(SACInstance));
|
||||
Length = instance.Info.Duration / 1000f;
|
||||
ok = instance.Opened;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
CLog.LogError("Error opening video file: " + _FileName);
|
||||
return false;
|
||||
}
|
||||
|
||||
int videoStreamIndex;
|
||||
SACDecoder videodecoder;
|
||||
try
|
||||
{
|
||||
_Videodecoder = CAcinerella.AcCreateVideoDecoder(_Instance);
|
||||
videodecoder = (SACDecoder)Marshal.PtrToStructure(_Videodecoder, typeof(SACDecoder));
|
||||
videoStreamIndex = videodecoder.StreamIndex;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
CLog.LogError("Error opening video file (can't find decoder): " + _FileName);
|
||||
_Free();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (videoStreamIndex < 0)
|
||||
{
|
||||
_Free();
|
||||
return false;
|
||||
}
|
||||
|
||||
_Width = videodecoder.StreamInfo.VideoInfo.FrameWidth;
|
||||
_Height = videodecoder.StreamInfo.VideoInfo.FrameHeight;
|
||||
|
||||
if (videodecoder.StreamInfo.VideoInfo.FramesPerSecond > 0)
|
||||
_FrameDuration = 1f / (float)videodecoder.StreamInfo.VideoInfo.FramesPerSecond;
|
||||
|
||||
_LastDecodedTime = 0f;
|
||||
_SetTime = 0f;
|
||||
|
||||
_Framebuffer.Init(_Width * _Height * 4);
|
||||
_FrameAvailable = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
private void _Decode()
|
||||
{
|
||||
const int minFrameDropCount = 4;
|
||||
|
||||
if (_Paused || _NoMoreFrames)
|
||||
return;
|
||||
|
||||
float videoTime = _Time + _Gap;
|
||||
float timeDifference = videoTime - _LastDecodedTime;
|
||||
|
||||
bool dropFrame = timeDifference >= (minFrameDropCount - 1) * _FrameDuration;
|
||||
|
||||
if (_Terminated)
|
||||
return;
|
||||
|
||||
bool frameFinished = false;
|
||||
if (dropFrame)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (videoTime >= Length)
|
||||
{
|
||||
if (_Loop)
|
||||
{
|
||||
lock (_MutexSyncSignals)
|
||||
{
|
||||
_Start = 0;
|
||||
_Gap = 0f;
|
||||
_SetTime = 0;
|
||||
}
|
||||
_Skip();
|
||||
}
|
||||
else
|
||||
{
|
||||
_NoMoreFrames = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var frameDropCount = (int)(timeDifference / _FrameDuration);
|
||||
frameFinished = CAcinerella.AcSkipFrames(_Instance, _Videodecoder, frameDropCount);
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
CLog.LogError("Error AcSkipFrame " + _FileName);
|
||||
}
|
||||
}
|
||||
|
||||
if (!frameFinished)
|
||||
{
|
||||
try
|
||||
{
|
||||
frameFinished = CAcinerella.AcGetFrame(_Instance, _Videodecoder);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
CLog.LogError("Error AcGetFrame " + _FileName);
|
||||
}
|
||||
}
|
||||
if (frameFinished)
|
||||
_FrameAvailable = true;
|
||||
else
|
||||
{
|
||||
if (_Loop)
|
||||
{
|
||||
lock (_MutexSyncSignals)
|
||||
{
|
||||
_Start = 0f;
|
||||
_Gap = 0f;
|
||||
_SetTime = 0f;
|
||||
}
|
||||
_Skip();
|
||||
}
|
||||
else
|
||||
_NoMoreFrames = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void _Copy()
|
||||
{
|
||||
var videodecoder = (SACDecoder)Marshal.PtrToStructure(_Videodecoder, typeof(SACDecoder));
|
||||
if (videodecoder.Buffer == IntPtr.Zero)
|
||||
return;
|
||||
_LastDecodedTime = (float)videodecoder.Timecode;
|
||||
_Framebuffer.Put(videodecoder.Buffer, _LastDecodedTime);
|
||||
_FrameAvailable = false;
|
||||
}
|
||||
|
||||
private void _UploadNewFrame(ref CTexture frame)
|
||||
{
|
||||
lock (_MutexFramebuffer)
|
||||
{
|
||||
CFrame curFrame = _FindFrame();
|
||||
|
||||
if (curFrame != null)
|
||||
{
|
||||
CDraw.UpdateOrAddTexture(ref frame, _Width, _Height, curFrame.Data);
|
||||
|
||||
lock (_MutexSyncSignals)
|
||||
{
|
||||
_LastShownTime = curFrame.Time;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_NoMoreFrames && _Framebuffer.IsEmpty())
|
||||
Finished = true;
|
||||
}
|
||||
}
|
||||
if (!Finished && _IsSleeping)
|
||||
{
|
||||
_IsSleeping = false;
|
||||
_EvWakeUp.Set();
|
||||
}
|
||||
}
|
||||
|
||||
private CFrame _FindFrame()
|
||||
{
|
||||
CFrame result = null;
|
||||
float now = _SetTime + _Gap;
|
||||
float maxEnd = now - _FrameDuration * 2; //Get only frames younger than 2
|
||||
CFrame frame;
|
||||
bool paused = _Paused;
|
||||
while ((frame = _Framebuffer.Get()) != null)
|
||||
{
|
||||
float frameEnd = frame.Time + _FrameDuration;
|
||||
//Don't show frames that are shown during or after now
|
||||
if (frameEnd >= now)
|
||||
break; //All following frames are after that one
|
||||
if (paused) // Don't modify anything
|
||||
break;
|
||||
_Framebuffer.SetRead();
|
||||
//Get the last(newest) possible frame and skip the rest to force in-order showing
|
||||
if (frameEnd <= maxEnd)
|
||||
continue;
|
||||
maxEnd = frameEnd;
|
||||
result = frame;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void _Free()
|
||||
{
|
||||
if (_Videodecoder != IntPtr.Zero)
|
||||
CAcinerella.AcFreeDecoder(_Videodecoder);
|
||||
|
||||
if (_Instance != IntPtr.Zero)
|
||||
{
|
||||
CAcinerella.AcClose(_Instance);
|
||||
CAcinerella.AcFree(_Instance);
|
||||
}
|
||||
}
|
||||
#endregion Threading
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,439 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using Vocaluxe.Base;
|
||||
using VocaluxeLib.Draw;
|
||||
|
||||
namespace Vocaluxe.Lib.Video.Acinerella
|
||||
{
|
||||
//This class describes a thread decoding a video
|
||||
//All public methods are meant to be called from "reader" thread only
|
||||
//Most others are to be called by this thread (_Thread instance) only!
|
||||
class CDecoderThread
|
||||
{
|
||||
private const float _LoopedRequestTime = -0.001f; //Magic const to detect if decoder looped automaticly
|
||||
|
||||
private Thread _Thread;
|
||||
private readonly Object _BufferMutex = new Object();
|
||||
|
||||
private IntPtr _Instance = IntPtr.Zero; // acinerella instance
|
||||
private IntPtr _Videodecoder = IntPtr.Zero; // acinerella video decoder instance
|
||||
|
||||
private readonly CFramebuffer _Framebuffer;
|
||||
private float _LastDecodedTime; // time of last decoded frame
|
||||
private float _LastShownTime = -1f; // time if the last shown frame in s IMPORTANT: Write only in context of reader
|
||||
// time of last requested frame aka current should-be position (_LastDecodedTime should be >=_RequestTime)
|
||||
//HAS to be < Length
|
||||
public float RequestTime { get; private set; }
|
||||
private bool _Paused;
|
||||
|
||||
private String _FileName;
|
||||
private float _FrameDuration; // frame time in s
|
||||
private int _Width;
|
||||
private int _Height;
|
||||
|
||||
private bool _RequestSkip;
|
||||
private bool _Terminated;
|
||||
private bool _FrameAvailable;
|
||||
private bool _NoMoreFrames;
|
||||
private readonly AutoResetEvent _EvWakeUp = new AutoResetEvent(false);
|
||||
private readonly AutoResetEvent _EvNoMoreFrames = new AutoResetEvent(false);
|
||||
private bool _IsSleeping;
|
||||
private int _WaitCount;
|
||||
|
||||
public float Length { get; private set; }
|
||||
public bool Loop { get; set; }
|
||||
|
||||
public CDecoderThread()
|
||||
{
|
||||
_Framebuffer = new CFramebuffer(10);
|
||||
_FrameDuration = 0.02f; // Set a reasonable standard till correct value is set
|
||||
}
|
||||
|
||||
//Open the file and get the length.
|
||||
public bool LoadFile(String fileName)
|
||||
{
|
||||
_FileName = fileName;
|
||||
try
|
||||
{
|
||||
_Instance = CAcinerella.AcInit();
|
||||
CAcinerella.AcOpen2(_Instance, fileName);
|
||||
|
||||
var instance = (SACInstance)Marshal.PtrToStructure(_Instance, typeof(SACInstance));
|
||||
Length = instance.Info.Duration / 1000f;
|
||||
bool ok = instance.Opened && Length > 0.001f;
|
||||
if (ok)
|
||||
return true;
|
||||
_Free();
|
||||
}
|
||||
catch (Exception) {}
|
||||
CLog.LogError("Error opening video file: " + _FileName);
|
||||
_Instance = IntPtr.Zero;
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool Start()
|
||||
{
|
||||
if (_Instance == IntPtr.Zero)
|
||||
{
|
||||
CLog.LogError("Tried to start a video file that is not open: " + _FileName);
|
||||
return false;
|
||||
}
|
||||
if (_Thread != null)
|
||||
{
|
||||
CLog.LogError("Tried to start a video file that is already started: " + _FileName);
|
||||
return false;
|
||||
}
|
||||
RequestTime = 0f;
|
||||
_Thread = new Thread(_Execute) {Priority = ThreadPriority.Normal, Name = Path.GetFileName(_FileName)};
|
||||
_Thread.Start();
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
_Terminated = true;
|
||||
_EvWakeUp.Set();
|
||||
_EvNoMoreFrames.Set();
|
||||
}
|
||||
|
||||
public void Pause()
|
||||
{
|
||||
if (_Paused)
|
||||
return;
|
||||
_Paused = true;
|
||||
}
|
||||
|
||||
public void Resume()
|
||||
{
|
||||
if (!_Paused)
|
||||
return;
|
||||
_Paused = false;
|
||||
}
|
||||
|
||||
//Sets the position to the given time discarding all decoded frames
|
||||
public void Skip(float time)
|
||||
{
|
||||
//Problem: This is not threadsave
|
||||
//Scenario: Clear buffer from main thread, decoder is in _Decode or _Copy
|
||||
//Result: Cleared buffer contains 1 old item. This is a problem when skipping back: E.g. Loop:
|
||||
//Old item has time=Length->Will not get removed
|
||||
//Workaround: Check in _FindFrame to remove first old item
|
||||
//Fix: Use mutex (TODO: Check overhead)
|
||||
lock (_BufferMutex) //Cover clear, RequestTime=, _RequestSkip=
|
||||
{
|
||||
_Framebuffer.Clear();
|
||||
RequestTime = time;
|
||||
_LastShownTime = time - _FrameDuration; //Set this to time to detect overflow of time in FindFrame but subtract FrameDuration so GetFrame will get the first frame
|
||||
_RequestSkip = true;
|
||||
}
|
||||
_EvNoMoreFrames.Set();
|
||||
}
|
||||
|
||||
private CFramebuffer.CFrame _FindFrame(float now)
|
||||
{
|
||||
CFramebuffer.CFrame result = null;
|
||||
CFramebuffer.CFrame frame;
|
||||
_Framebuffer.ResetStack();
|
||||
while ((frame = _Framebuffer.Pop()) != null)
|
||||
{
|
||||
//float frameEnd = frame.Time + _FrameDuration;
|
||||
float frameTime = frame.Time;
|
||||
|
||||
if (frameTime > now)
|
||||
{
|
||||
//2 Cases: all following frames are after this one, or we have a loop and 'now' wrapped over
|
||||
//First case is if we have no loop or we did not wrap or frame is before last one (last is the case if frame is already one of the new iterations, e.g. Last=19 now=1 frame=2)
|
||||
if (!Loop || _LastShownTime <= now || frameTime < _LastShownTime)
|
||||
break; //Following frames (incl this one) are after now, so do not consider any of them
|
||||
}
|
||||
// ReSharper disable CompareOfFloatsByEqualityOperator
|
||||
else if (Loop && RequestTime == _LoopedRequestTime)
|
||||
// ReSharper restore CompareOfFloatsByEqualityOperator
|
||||
{
|
||||
//Frame time might have wrapped but now did not
|
||||
if (frameTime < _LastShownTime && _LastShownTime <= now)
|
||||
break; //Following frames (incl this one) are after now, so do not consider any of them
|
||||
}
|
||||
//Get the last(newest) possible frame and skip the rest
|
||||
if (result != null)
|
||||
{
|
||||
//Frame is to old -> Discard
|
||||
result.SetRead();
|
||||
}
|
||||
result = frame;
|
||||
if (_Paused)
|
||||
break; //Just get 1 frame if paused otherwise a paused movie could move a bit
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a frame
|
||||
/// </summary>
|
||||
/// <param name="frame">Referenz to texture where frame should be put in (can be null, then texture is created)</param>
|
||||
/// <param name="time">Maximum start time for frame</param>
|
||||
/// <param name="finished">Set to whether there are no more frames (stream finished, no loop, future calls will always return false)</param>
|
||||
/// <returns>True if a new frame was gotten</returns>
|
||||
public bool GetFrame(ref CTexture frame, ref float time, out bool finished)
|
||||
{
|
||||
bool result;
|
||||
if (Math.Abs(_LastShownTime - time) < _FrameDuration && frame != null) //Check 1 frame difference
|
||||
{
|
||||
time = _LastShownTime;
|
||||
result = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
CFramebuffer.CFrame curFrame = _FindFrame(time);
|
||||
if (curFrame != null)
|
||||
{
|
||||
CDraw.UpdateOrAddTexture(ref frame, _Width, _Height, curFrame.Data);
|
||||
if (!_Paused)
|
||||
curFrame.SetRead();
|
||||
time = curFrame.Time;
|
||||
_LastShownTime = time;
|
||||
result = frame != null;
|
||||
}
|
||||
else
|
||||
result = false;
|
||||
|
||||
if (_IsSleeping)
|
||||
{
|
||||
_IsSleeping = false;
|
||||
_EvWakeUp.Set();
|
||||
}
|
||||
}
|
||||
finished = _NoMoreFrames && _Framebuffer.IsEmpty();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//Time should be < Length
|
||||
public void SyncTime(float time)
|
||||
{
|
||||
if (_Thread == null)
|
||||
return; //Not initialized
|
||||
|
||||
if (RequestTime - time >= _FrameDuration)
|
||||
{
|
||||
//Jump back more than 1 frame. To guarantee the order in the buffer use Skip() which clears the buffer
|
||||
Skip(time);
|
||||
}
|
||||
else if (time - RequestTime >= _FrameDuration)
|
||||
{
|
||||
//we were more than 1 frame to slow -> Jump forward (This is save, as the decoder will skip frames if necessary)
|
||||
// ReSharper disable CompareOfFloatsByEqualityOperator
|
||||
if (Loop && RequestTime == _LoopedRequestTime)
|
||||
// ReSharper restore CompareOfFloatsByEqualityOperator
|
||||
{
|
||||
//In a loop our decoder may have reset RequestTime to 0 but we want a frame from the end of the video
|
||||
//Skipping forward is fatal as it resets the decoder to decode already decoded frames causing lags
|
||||
//So first check if we have a valid frame in our buffer
|
||||
_Framebuffer.ResetStack();
|
||||
CFramebuffer.CFrame frame;
|
||||
while ((frame = _Framebuffer.Pop()) != null)
|
||||
{
|
||||
if (frame.Time + _FrameDuration >= time)
|
||||
return;
|
||||
}
|
||||
//If we don't the Length might be inaccurate (e.g. last frame ends at 19.98 but Length=20)
|
||||
if (time >= Length - 2 * _FrameDuration)
|
||||
return;
|
||||
}
|
||||
|
||||
RequestTime = time;
|
||||
}
|
||||
}
|
||||
|
||||
private bool _OpenVideoStream()
|
||||
{
|
||||
int videoStreamIndex;
|
||||
SACDecoder decoder;
|
||||
try
|
||||
{
|
||||
_Videodecoder = CAcinerella.AcCreateVideoDecoder(_Instance);
|
||||
decoder = (SACDecoder)Marshal.PtrToStructure(_Videodecoder, typeof(SACDecoder));
|
||||
videoStreamIndex = decoder.StreamIndex;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
CLog.LogError("Error opening video file (can't find decoder): " + _FileName);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (videoStreamIndex < 0)
|
||||
return false;
|
||||
|
||||
_Width = decoder.StreamInfo.VideoInfo.FrameWidth;
|
||||
_Height = decoder.StreamInfo.VideoInfo.FrameHeight;
|
||||
|
||||
if (decoder.StreamInfo.VideoInfo.FramesPerSecond > 0)
|
||||
_FrameDuration = 1f / (float)decoder.StreamInfo.VideoInfo.FramesPerSecond;
|
||||
|
||||
_Framebuffer.Init(_Width * _Height * 4);
|
||||
_FrameAvailable = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
//Just call this if thread is not alive
|
||||
private void _Free()
|
||||
{
|
||||
if (_Videodecoder != IntPtr.Zero)
|
||||
CAcinerella.AcFreeDecoder(_Videodecoder);
|
||||
|
||||
if (_Instance != IntPtr.Zero)
|
||||
{
|
||||
CAcinerella.AcClose(_Instance);
|
||||
CAcinerella.AcFree(_Instance);
|
||||
}
|
||||
}
|
||||
|
||||
// Skip to a given time (in s)
|
||||
private void _Skip()
|
||||
{
|
||||
float skipTime = RequestTime; //Copy to variable to have consistent checks
|
||||
if (skipTime < 0 || skipTime >= Length)
|
||||
skipTime = 0;
|
||||
|
||||
try
|
||||
{
|
||||
CAcinerella.AcSeek(_Videodecoder, -1, (Int64)(skipTime * 1000f));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
CLog.LogError("Error seeking video file \"" + _FileName + "\": " + e.Message);
|
||||
}
|
||||
_LastDecodedTime = skipTime;
|
||||
|
||||
_FrameAvailable = false;
|
||||
}
|
||||
|
||||
private void _Decode()
|
||||
{
|
||||
const int minFrameDropCount = 4;
|
||||
|
||||
if (_NoMoreFrames)
|
||||
return;
|
||||
|
||||
float videoTime = RequestTime;
|
||||
float timeDifference = videoTime - _LastDecodedTime;
|
||||
|
||||
bool dropFrame = timeDifference >= (minFrameDropCount - 1) * _FrameDuration;
|
||||
|
||||
bool hasFrameDecoded = false;
|
||||
if (dropFrame)
|
||||
{
|
||||
try
|
||||
{
|
||||
var frameDropCount = (int)Math.Ceiling(timeDifference / _FrameDuration);
|
||||
// Add 1 dropped frame per 16 frames (Power of 2 -> Div is fast) as skipping takes time too and we don't want to skip again
|
||||
frameDropCount += frameDropCount / 16;
|
||||
hasFrameDecoded = CAcinerella.AcSkipFrames(_Instance, _Videodecoder, frameDropCount);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
CLog.LogError("Error AcSkipFrame " + _FileName);
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasFrameDecoded)
|
||||
{
|
||||
try
|
||||
{
|
||||
hasFrameDecoded = CAcinerella.AcGetFrame(_Instance, _Videodecoder);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
CLog.LogError("Error AcGetFrame " + _FileName);
|
||||
}
|
||||
}
|
||||
if (hasFrameDecoded)
|
||||
_FrameAvailable = true;
|
||||
else
|
||||
{
|
||||
if (Loop)
|
||||
{
|
||||
RequestTime = _LoopedRequestTime;
|
||||
_Skip();
|
||||
}
|
||||
else
|
||||
_NoMoreFrames = true;
|
||||
}
|
||||
}
|
||||
|
||||
//Copies a frame to the buffer but does not set it as 'written'
|
||||
//Returns true if frame data is now in buffer
|
||||
private bool _CopyDecodedFrameToBuffer()
|
||||
{
|
||||
bool result;
|
||||
var decoder = (SACDecoder)Marshal.PtrToStructure(_Videodecoder, typeof(SACDecoder));
|
||||
if (decoder.Buffer != IntPtr.Zero)
|
||||
{
|
||||
_LastDecodedTime = (float)decoder.Timecode;
|
||||
result = _Framebuffer.Put(decoder.Buffer, _LastDecodedTime);
|
||||
}
|
||||
else
|
||||
result = false;
|
||||
_FrameAvailable = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
private void _Execute()
|
||||
{
|
||||
if (!_OpenVideoStream())
|
||||
{
|
||||
_Free();
|
||||
Stop();
|
||||
}
|
||||
|
||||
while (!_Terminated)
|
||||
{
|
||||
if (_NoMoreFrames)
|
||||
_EvNoMoreFrames.WaitOne();
|
||||
if (_RequestSkip)
|
||||
{
|
||||
_RequestSkip = false;
|
||||
_NoMoreFrames = false;
|
||||
_Skip();
|
||||
}
|
||||
|
||||
if (!_FrameAvailable)
|
||||
_Decode();
|
||||
|
||||
//Bail out if we want to skip
|
||||
if (!_RequestSkip && _FrameAvailable)
|
||||
{
|
||||
if (!_Framebuffer.IsFull())
|
||||
{
|
||||
if (_CopyDecodedFrameToBuffer())
|
||||
{
|
||||
//Do not write to buffer if we want to skip. So check and write have to be done atomicly
|
||||
lock (_BufferMutex)
|
||||
{
|
||||
if (_RequestSkip)
|
||||
continue; //Frame is invalid if we want to skip
|
||||
_Framebuffer.SetWritten();
|
||||
}
|
||||
}
|
||||
_WaitCount = 0;
|
||||
Thread.Sleep(5); //Sleep for a bit to give other threads an opportunity to run
|
||||
}
|
||||
else if (_WaitCount > 3)
|
||||
{
|
||||
_IsSleeping = true;
|
||||
_EvWakeUp.WaitOne();
|
||||
}
|
||||
else
|
||||
{
|
||||
Thread.Sleep((int)(_Framebuffer.Size * _FrameDuration * 1000 / 2));
|
||||
_WaitCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_Free();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,24 +20,35 @@ using System.Runtime.InteropServices;
|
||||
|
||||
namespace Vocaluxe.Lib.Video.Acinerella
|
||||
{
|
||||
class CFrame
|
||||
{
|
||||
public readonly byte[] Data;
|
||||
public float Time = -1;
|
||||
|
||||
public CFrame(int dataSize)
|
||||
{
|
||||
Data = new byte[dataSize];
|
||||
}
|
||||
}
|
||||
|
||||
class CFramebuffer
|
||||
{
|
||||
public class CFrame
|
||||
{
|
||||
private readonly CFramebuffer _Parent;
|
||||
private readonly int _Index;
|
||||
public readonly byte[] Data;
|
||||
public float Time = -1;
|
||||
|
||||
public CFrame(CFramebuffer parent, int index, int dataSize)
|
||||
{
|
||||
_Parent = parent;
|
||||
_Index = index;
|
||||
Data = new byte[dataSize];
|
||||
}
|
||||
|
||||
//Only call from reader thread
|
||||
public void SetRead()
|
||||
{
|
||||
_Parent._SetRead(_Index);
|
||||
}
|
||||
}
|
||||
|
||||
private readonly CFrame[] _Frames;
|
||||
private readonly int _Size;
|
||||
private int _DataSize;
|
||||
private int _Last;
|
||||
private int _First;
|
||||
private int _Next;
|
||||
private bool _Initialized;
|
||||
|
||||
public int Size
|
||||
@@ -45,21 +56,24 @@ namespace Vocaluxe.Lib.Video.Acinerella
|
||||
get { return _Size; }
|
||||
}
|
||||
|
||||
// Constructs a framebuffer with max. size frames
|
||||
public CFramebuffer(int size)
|
||||
{
|
||||
_Size = size;
|
||||
_Frames = new CFrame[size];
|
||||
}
|
||||
|
||||
// Initializes the framebuffer with the size of each frame
|
||||
// MUST be called before all others
|
||||
public void Init(int dataSize)
|
||||
{
|
||||
_DataSize = dataSize;
|
||||
for (int i = 0; i < _Size; i++)
|
||||
_Frames[i] = new CFrame(dataSize);
|
||||
_Frames[i] = new CFrame(this, i, dataSize);
|
||||
_Initialized = true;
|
||||
}
|
||||
|
||||
private int _Next(int current)
|
||||
private int _GetNextIndex(int current)
|
||||
{
|
||||
current++;
|
||||
return (current < _Size) ? current : 0;
|
||||
@@ -67,7 +81,7 @@ namespace Vocaluxe.Lib.Video.Acinerella
|
||||
|
||||
public bool IsFull()
|
||||
{
|
||||
return _Next(_Last) == _First;
|
||||
return _GetNextIndex(_Last) == _First;
|
||||
}
|
||||
|
||||
public bool IsEmpty()
|
||||
@@ -75,6 +89,7 @@ namespace Vocaluxe.Lib.Video.Acinerella
|
||||
return _First == _Last;
|
||||
}
|
||||
|
||||
//Only call from writer thread
|
||||
public bool Put(IntPtr data, float time)
|
||||
{
|
||||
if (!_Initialized || IsFull())
|
||||
@@ -82,27 +97,43 @@ namespace Vocaluxe.Lib.Video.Acinerella
|
||||
CFrame frame = _Frames[_Last];
|
||||
Marshal.Copy(data, frame.Data, 0, _DataSize);
|
||||
frame.Time = time;
|
||||
_Last = _Next(_Last);
|
||||
return true;
|
||||
}
|
||||
|
||||
public CFrame Get()
|
||||
//Only call from writer thread after succesfull put
|
||||
public void SetWritten()
|
||||
{
|
||||
return IsEmpty() ? null : _Frames[_First];
|
||||
_Last = _GetNextIndex(_Last);
|
||||
}
|
||||
|
||||
public bool SetRead()
|
||||
//Only call from reader thread
|
||||
public void ResetStack()
|
||||
{
|
||||
if (IsEmpty())
|
||||
return false;
|
||||
_First = _Next(_First);
|
||||
return true;
|
||||
_Next = _First;
|
||||
}
|
||||
|
||||
//Pops the next frame if available
|
||||
//You have to call ResetNext before the first call to this function and call the CFrame.SetRead to free the buffers
|
||||
//Only call from reader thread
|
||||
public CFrame Pop()
|
||||
{
|
||||
if (_Next == _Last)
|
||||
return null;
|
||||
CFrame res = _Frames[_Next];
|
||||
_Next = _GetNextIndex(_Next);
|
||||
return res;
|
||||
}
|
||||
|
||||
private void _SetRead(int index)
|
||||
{
|
||||
if ((_First <= index && (index < _Next || _Next < _First)) || (_Next < _First && index < _Next))
|
||||
_First = _GetNextIndex(index);
|
||||
}
|
||||
|
||||
//Only call from reader thread
|
||||
public void Clear()
|
||||
{
|
||||
_First = 0;
|
||||
_Last = 0;
|
||||
_Next = _First = _Last;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -259,6 +259,7 @@ namespace Vocaluxe
|
||||
Environment.Exit(Environment.ExitCode);
|
||||
}
|
||||
|
||||
#if !DEBUG
|
||||
[HandleProcessCorruptedStateExceptions]
|
||||
private static void UnhandledExceptionHandler(object sender, UnhandledExceptionEventArgs args)
|
||||
{
|
||||
@@ -273,6 +274,7 @@ namespace Vocaluxe
|
||||
CLog.LogError("Unhandled exception: " + e.Message + stackTrace);
|
||||
_CloseProgram();
|
||||
}
|
||||
#endif
|
||||
|
||||
private static Assembly _AssemblyResolver(Object sender, ResolveEventArgs args)
|
||||
{
|
||||
|
||||
@@ -49,5 +49,5 @@ using System.Runtime.InteropServices;
|
||||
// Revision
|
||||
//
|
||||
|
||||
[assembly: AssemblyVersion("0.3.0.82")]
|
||||
[assembly: AssemblyFileVersion("0.3.0.82")]
|
||||
[assembly: AssemblyVersion("0.3.0.83")]
|
||||
[assembly: AssemblyFileVersion("0.3.0.83")]
|
||||
@@ -15,7 +15,6 @@
|
||||
// along with Vocaluxe. If not, see <http://www.gnu.org/licenses/>.
|
||||
#endregion
|
||||
|
||||
using ServerLib;
|
||||
using Vocaluxe.Base;
|
||||
using Vocaluxe.Base.Server;
|
||||
using VocaluxeLib;
|
||||
@@ -56,11 +55,6 @@ namespace Vocaluxe.Screens
|
||||
_ThemeTexts = new string[] {_TextServerAddress, _TextServerNotRunning};
|
||||
}
|
||||
|
||||
public override void LoadTheme(string xmlPath)
|
||||
{
|
||||
base.LoadTheme(xmlPath);
|
||||
}
|
||||
|
||||
public override void OnShow()
|
||||
{
|
||||
base.OnShow();
|
||||
|
||||
@@ -183,24 +183,28 @@ namespace Vocaluxe.Screens
|
||||
|
||||
public override void LoadTheme(string xmlPath)
|
||||
{
|
||||
bool ressourceOK = true;
|
||||
//Vocaluxe-Logo
|
||||
CDataBase.GetCreditsRessource("Logo_voc.png", ref _TexLogo);
|
||||
ressourceOK &= CDataBase.GetCreditsRessource("Logo_voc.png", ref _TexLogo);
|
||||
|
||||
//Little stars for logo
|
||||
CDataBase.GetCreditsRessource("PerfectNoteStar.png", ref _TexPerfectNoteStar);
|
||||
ressourceOK &= CDataBase.GetCreditsRessource("PerfectNoteStar.png", ref _TexPerfectNoteStar);
|
||||
|
||||
CDataBase.GetCreditsRessource("redDot.png", ref _TexRedDot);
|
||||
CDataBase.GetCreditsRessource("blueDot.png", ref _TexBlueDot);
|
||||
ressourceOK &= CDataBase.GetCreditsRessource("redDot.png", ref _TexRedDot);
|
||||
ressourceOK &= CDataBase.GetCreditsRessource("blueDot.png", ref _TexBlueDot);
|
||||
|
||||
CDataBase.GetCreditsRessource("brunzel.png", ref _TexNameBrunzel);
|
||||
CDataBase.GetCreditsRessource("Darkice.png", ref _TexNameDarkice);
|
||||
CDataBase.GetCreditsRessource("flokuep.png", ref _TexNameFlokuep);
|
||||
CDataBase.GetCreditsRessource("flamefire.png", ref _TexNameFlamefire);
|
||||
CDataBase.GetCreditsRessource("bohning.png", ref _TexNameBohning);
|
||||
CDataBase.GetCreditsRessource("mesand.png", ref _TexNameMesand);
|
||||
CDataBase.GetCreditsRessource("babene03.png", ref _TexNameBabene03);
|
||||
CDataBase.GetCreditsRessource("pantero.png", ref _TexNamePantero);
|
||||
CDataBase.GetCreditsRessource("Pinky007.png", ref _TexNamePinky007);
|
||||
ressourceOK &= CDataBase.GetCreditsRessource("brunzel.png", ref _TexNameBrunzel);
|
||||
ressourceOK &= CDataBase.GetCreditsRessource("Darkice.png", ref _TexNameDarkice);
|
||||
ressourceOK &= CDataBase.GetCreditsRessource("flokuep.png", ref _TexNameFlokuep);
|
||||
ressourceOK &= CDataBase.GetCreditsRessource("flamefire.png", ref _TexNameFlamefire);
|
||||
ressourceOK &= CDataBase.GetCreditsRessource("bohning.png", ref _TexNameBohning);
|
||||
ressourceOK &= CDataBase.GetCreditsRessource("mesand.png", ref _TexNameMesand);
|
||||
ressourceOK &= CDataBase.GetCreditsRessource("babene03.png", ref _TexNameBabene03);
|
||||
ressourceOK &= CDataBase.GetCreditsRessource("pantero.png", ref _TexNamePantero);
|
||||
ressourceOK &= CDataBase.GetCreditsRessource("Pinky007.png", ref _TexNamePinky007);
|
||||
|
||||
if (!ressourceOK)
|
||||
CLog.LogError("Could not load all ressources!", true, true);
|
||||
|
||||
//Prepare Text
|
||||
int lastY = 280;
|
||||
|
||||
@@ -44,7 +44,7 @@ namespace Vocaluxe.Screens
|
||||
private string[] _TextDate;
|
||||
private string[] _ParticleEffectNew;
|
||||
|
||||
private List<SScores>[] _Scores;
|
||||
private List<SDBScoreEntry>[] _Scores;
|
||||
private List<int> _NewEntryIDs;
|
||||
private int _Round;
|
||||
private int _Pos;
|
||||
@@ -169,7 +169,7 @@ namespace Vocaluxe.Screens
|
||||
string name = _Scores[_Round][_Pos + p].Name;
|
||||
name += " [" + CLanguage.Translate(Enum.GetName(typeof(EGameDifficulty), _Scores[_Round][_Pos + p].Difficulty)) + "]";
|
||||
if (_IsDuet)
|
||||
name += " (P" + (_Scores[_Round][_Pos + p].LineNr + 1) + ")";
|
||||
name += " (P" + (_Scores[_Round][_Pos + p].VoiceNr + 1) + ")";
|
||||
_Texts[_TextName[p]].Text = name;
|
||||
|
||||
_Texts[_TextScore[p]].Text = _Scores[_Round][_Pos + p].Score.ToString("00000");
|
||||
@@ -194,10 +194,6 @@ namespace Vocaluxe.Screens
|
||||
base.OnShow();
|
||||
_Round = 0;
|
||||
_Pos = 0;
|
||||
CPoints points = CGame.GetPoints();
|
||||
_Scores = new List<SScores>[points.NumRounds];
|
||||
for (int i = 0; i < _Scores.Length; i++)
|
||||
_Scores[i] = new List<SScores>();
|
||||
_NewEntryIDs.Clear();
|
||||
_AddScoresToDB();
|
||||
_LoadScores();
|
||||
@@ -231,15 +227,14 @@ namespace Vocaluxe.Screens
|
||||
|
||||
private void _LoadScores()
|
||||
{
|
||||
CPoints points = CGame.GetPoints();
|
||||
if (points == null)
|
||||
return;
|
||||
|
||||
_Pos = 0;
|
||||
for (int round = 0; round < points.NumRounds; round++)
|
||||
int rounds = CGame.NumRounds;
|
||||
_Scores = new List<SDBScoreEntry>[rounds];
|
||||
for (int round = 0; round < rounds; round++)
|
||||
{
|
||||
SPlayer player = points.GetPlayer(round, CGame.NumPlayer)[0];
|
||||
CDataBase.LoadScore(out _Scores[round], player);
|
||||
int songID = CGame.GetSong(round).ID;
|
||||
EGameMode gameMode = CGame.GetGameMode(round);
|
||||
_Scores[round] = CDataBase.LoadScore(songID, gameMode);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -247,7 +242,7 @@ namespace Vocaluxe.Screens
|
||||
{
|
||||
_IsDuet = false;
|
||||
CPoints points = CGame.GetPoints();
|
||||
CSong song = CGame.GetSong(_Round + 1);
|
||||
CSong song = CGame.GetSong(_Round);
|
||||
if (song == null)
|
||||
return;
|
||||
|
||||
@@ -255,7 +250,7 @@ namespace Vocaluxe.Screens
|
||||
if (points.NumRounds > 1)
|
||||
_Texts[_TextSongName].Text += " (" + (_Round + 1) + "/" + points.NumRounds + ")";
|
||||
|
||||
switch (CGame.GetGameMode(_Round + 1))
|
||||
switch (CGame.GetGameMode(_Round))
|
||||
{
|
||||
case EGameMode.TR_GAMEMODE_NORMAL:
|
||||
_Texts[_TextSongMode].Text = "TR_GAMEMODE_NORMAL";
|
||||
@@ -284,28 +279,20 @@ namespace Vocaluxe.Screens
|
||||
|
||||
private void _ChangePos(int num)
|
||||
{
|
||||
if (num > 0)
|
||||
{
|
||||
if (_Pos + num + _NumEntrys < _Scores[_Round].Count)
|
||||
_Pos += num;
|
||||
}
|
||||
if (num < 0)
|
||||
if (_Scores[_Round].Count == 0)
|
||||
_Pos = 0;
|
||||
else
|
||||
{
|
||||
_Pos += num;
|
||||
if (_Pos < 0)
|
||||
_Pos = 0;
|
||||
_Pos = _Pos.Clamp(0, _Scores[_Round].Count - 1);
|
||||
}
|
||||
}
|
||||
|
||||
private void _ChangeRound(int num)
|
||||
{
|
||||
CPoints points = CGame.GetPoints();
|
||||
if (_Round + num < points.NumRounds && _Round + num > -1)
|
||||
_Round += num;
|
||||
else if (_Round + num >= points.NumRounds)
|
||||
_Round = points.NumRounds - 1;
|
||||
else if (_Round + num < 0)
|
||||
_Round = 0;
|
||||
_Round += num;
|
||||
_Round = _Round.Clamp(0, points.NumRounds - 1);
|
||||
_UpdateRound();
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
// along with Vocaluxe. If not, see <http://www.gnu.org/licenses/>.
|
||||
#endregion
|
||||
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
using Vocaluxe.Base;
|
||||
@@ -38,9 +37,8 @@ namespace Vocaluxe.Screens
|
||||
private readonly string[] _IntroVideo = new string[] {"IntroIn", "IntroMid", "IntroOut"};
|
||||
|
||||
private Thread _SongLoaderThread;
|
||||
private Stopwatch _Timer;
|
||||
private bool _SkipIntro;
|
||||
private int _CurrentIntroVideoNr;
|
||||
private int _CurrentIntroVideo;
|
||||
private bool _IntroOutPlayed;
|
||||
private CVideoPlayer[] _Intros;
|
||||
|
||||
@@ -54,7 +52,6 @@ namespace Vocaluxe.Screens
|
||||
_Intros = new CVideoPlayer[_IntroVideo.Length];
|
||||
for (int i = 0; i < _Intros.Length; i++)
|
||||
_Intros[i] = new CVideoPlayer();
|
||||
_Timer = new Stopwatch();
|
||||
}
|
||||
|
||||
public override bool HandleInput(SKeyEvent keyEvent)
|
||||
@@ -109,7 +106,7 @@ namespace Vocaluxe.Screens
|
||||
CLanguage.Translate("TR_SCREENLOAD_LOADED") + ")";
|
||||
|
||||
_SkipIntro = false;
|
||||
_CurrentIntroVideoNr = -1;
|
||||
_CurrentIntroVideo = -1;
|
||||
_IntroOutPlayed = false;
|
||||
|
||||
if (CConfig.VideoBackgrounds == EOffOn.TR_CONFIG_ON)
|
||||
@@ -135,7 +132,6 @@ namespace Vocaluxe.Screens
|
||||
CLog.StartBenchmark(0, "Load Songs Full");
|
||||
_SongLoaderThread.IsBackground = true;
|
||||
_SongLoaderThread.Start();
|
||||
_Timer.Start();
|
||||
|
||||
if (CConfig.BackgroundMusic == EOffOn.TR_CONFIG_ON &&
|
||||
CConfig.BackgroundMusicSource == EBackgroundMusicSource.TR_CONFIG_NO_OWN_MUSIC && !_BGMusicStarted)
|
||||
@@ -155,11 +151,6 @@ namespace Vocaluxe.Screens
|
||||
{
|
||||
_CheckStartIntroVideos();
|
||||
|
||||
if (CSettings.GameState == EGameState.EditTheme)
|
||||
_Timer.Stop();
|
||||
else
|
||||
_Timer.Start();
|
||||
|
||||
bool next = CConfig.CoverLoading != ECoverLoading.TR_CONFIG_COVERLOADING_ATSTART || CSongs.CoverLoaded;
|
||||
|
||||
if ((_IntroOutPlayed || _SkipIntro) && next && CSettings.GameState != EGameState.EditTheme && CSongs.SongsLoaded)
|
||||
@@ -191,8 +182,8 @@ namespace Vocaluxe.Screens
|
||||
{
|
||||
_DrawBG();
|
||||
|
||||
foreach (CVideoPlayer videoPlayer in _Intros)
|
||||
videoPlayer.Draw();
|
||||
if (_CurrentIntroVideo >= 0 && _CurrentIntroVideo < _Intros.Length)
|
||||
_Intros[_CurrentIntroVideo].Draw();
|
||||
|
||||
_DrawFG();
|
||||
return true;
|
||||
@@ -201,8 +192,6 @@ namespace Vocaluxe.Screens
|
||||
public override void OnClose()
|
||||
{
|
||||
base.OnClose();
|
||||
_Timer.Stop();
|
||||
_Timer.Reset();
|
||||
|
||||
foreach (CVideoPlayer videoPlayer in _Intros)
|
||||
videoPlayer.Close();
|
||||
@@ -228,24 +217,24 @@ namespace Vocaluxe.Screens
|
||||
return;
|
||||
}
|
||||
|
||||
if (_CurrentIntroVideoNr < 0)
|
||||
if (_CurrentIntroVideo < 0)
|
||||
{
|
||||
_CurrentIntroVideoNr = 0;
|
||||
_CurrentIntroVideo = 0;
|
||||
_Intros[0].Start();
|
||||
}
|
||||
else if (_CurrentIntroVideoNr == 0 && _Intros[0].IsFinished && CConfig.CoverLoading == ECoverLoading.TR_CONFIG_COVERLOADING_ATSTART)
|
||||
else if (_CurrentIntroVideo == 0 && _Intros[0].IsFinished && CConfig.CoverLoading == ECoverLoading.TR_CONFIG_COVERLOADING_ATSTART)
|
||||
{
|
||||
_CurrentIntroVideoNr = 1;
|
||||
_CurrentIntroVideo = 1;
|
||||
_Intros[1].Loop = true;
|
||||
_Intros[1].Start();
|
||||
}
|
||||
else if ((_CurrentIntroVideoNr == 1 && CSongs.CoverLoaded) ||
|
||||
(_CurrentIntroVideoNr == 0 && _Intros[0].IsFinished))
|
||||
else if ((_CurrentIntroVideo == 1 && CSongs.CoverLoaded) ||
|
||||
(_CurrentIntroVideo == 0 && _Intros[0].IsFinished))
|
||||
{
|
||||
_CurrentIntroVideoNr = 2;
|
||||
_CurrentIntroVideo = 2;
|
||||
_Intros[2].Start();
|
||||
}
|
||||
else if (_CurrentIntroVideoNr == 2 && _Intros[2].IsFinished)
|
||||
else if (_CurrentIntroVideo == 2 && _Intros[2].IsFinished)
|
||||
_IntroOutPlayed = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -241,7 +241,7 @@ namespace Vocaluxe.Screens
|
||||
break;
|
||||
|
||||
case Keys.F10:
|
||||
if (CGame.GetNumSongs() == 1 && CGame.GetSong(1).IsDuet)
|
||||
if (CGame.GetNumSongs() == 1 && CGame.GetSong(0).IsDuet)
|
||||
{
|
||||
CSelectSlide selectSlideDuetPart = _SelectSlides[_SelectSlideDuetPlayer[_SelectingFastPlayerNr - 1]];
|
||||
selectSlideDuetPart.Selection = (selectSlideDuetPart.Selection + 1) % 2;
|
||||
@@ -599,7 +599,7 @@ namespace Vocaluxe.Screens
|
||||
_CheckMics();
|
||||
_CheckPlayers();
|
||||
|
||||
CSong firstSong = CGame.GetSong(1);
|
||||
CSong firstSong = CGame.GetSong(0);
|
||||
|
||||
for (int i = 0; i < CSettings.MaxNumPlayer; i++)
|
||||
{
|
||||
@@ -627,12 +627,11 @@ namespace Vocaluxe.Screens
|
||||
|
||||
private void _StartSong()
|
||||
{
|
||||
for (int i = 0; i < CGame.NumPlayer; i++)
|
||||
if (CGame.GetNumSongs() == 1 && CGame.GetSong(0).IsDuet)
|
||||
{
|
||||
if (CGame.GetNumSongs() == 1 && CGame.GetSong(1).IsDuet)
|
||||
for (int i = 0; i < CGame.NumPlayer; i++)
|
||||
CGame.Players[i].VoiceNr = _SelectSlides[_SelectSlideDuetPlayer[i]].Selection;
|
||||
}
|
||||
|
||||
CGraphics.FadeTo(EScreens.ScreenSing);
|
||||
}
|
||||
|
||||
@@ -658,7 +657,7 @@ namespace Vocaluxe.Screens
|
||||
if (_Texts["TextPlayer" + i].Text == "")
|
||||
_Texts["TextPlayer" + i].Text = CProfiles.GetPlayerName(-1, i);
|
||||
_Equalizers["EqualizerPlayer" + i].Visible = true;
|
||||
if (CGame.GetNumSongs() == 1 && CGame.GetSong(1).IsDuet)
|
||||
if (CGame.GetNumSongs() == 1 && CGame.GetSong(0).IsDuet)
|
||||
_SelectSlides["SelectSlideDuetPlayer" + i].Visible = true;
|
||||
}
|
||||
else
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using System.Windows.Forms;
|
||||
using Vocaluxe.Base;
|
||||
using Vocaluxe.Lib.Sound;
|
||||
@@ -26,21 +25,14 @@ using VocaluxeLib.Menu;
|
||||
|
||||
namespace Vocaluxe.Screens
|
||||
{
|
||||
struct SDelayTest
|
||||
{
|
||||
public Stopwatch Timer;
|
||||
public float Delay;
|
||||
}
|
||||
|
||||
class CScreenOptionsRecord : CMenu
|
||||
{
|
||||
// Version number for theme files. Increment it, if you've changed something on the theme files!
|
||||
protected override int _ScreenVersion
|
||||
{
|
||||
get { return 3; }
|
||||
get { return 4; }
|
||||
}
|
||||
|
||||
private const float _MaxDelayTime = 1f;
|
||||
private const string _SelectSlideRecordDevices = "SelectSlideRecordDevices";
|
||||
|
||||
private const string _SelectSlideRecordChannel1 = "SelectSlideRecordChannel1";
|
||||
@@ -53,6 +45,9 @@ namespace Vocaluxe.Screens
|
||||
private const string _ButtonExit = "ButtonExit";
|
||||
private const string _ButtonDelayTest = "ButtonDelayTest";
|
||||
|
||||
private const string _TextChannel1 = "TextChannel1";
|
||||
private const string _TextChannel2 = "TextChannel2";
|
||||
|
||||
private const string _TextDelayChannel1 = "TextDelayChannel1";
|
||||
private const string _TextDelayChannel2 = "TextDelayChannel2";
|
||||
|
||||
@@ -65,9 +60,7 @@ namespace Vocaluxe.Screens
|
||||
private ReadOnlyCollection<CRecordDevice> _Devices;
|
||||
private int _DeviceNr;
|
||||
|
||||
private SDelayTest[] _DelayTest;
|
||||
private bool _DelayTestRunning;
|
||||
private int _DelaySound;
|
||||
private readonly CDelayTest _DelayTest = new CDelayTest(2);
|
||||
|
||||
public override void Init()
|
||||
{
|
||||
@@ -77,7 +70,7 @@ namespace Vocaluxe.Screens
|
||||
values.AddRange(_StaticEnergyChannel);
|
||||
_ThemeStatics = values.ToArray();
|
||||
|
||||
_ThemeTexts = new string[] {_TextWarning, _TextDelayChannel1, _TextDelayChannel2};
|
||||
_ThemeTexts = new string[] {_TextWarning, _TextChannel1, _TextChannel2, _TextDelayChannel1, _TextDelayChannel2};
|
||||
_ThemeButtons = new string[] {_ButtonExit, _ButtonDelayTest};
|
||||
_ThemeSelectSlides = new string[] {_SelectSlideRecordDevices, _SelectSlideRecordChannel1, _SelectSlideRecordChannel2, _SelectSlideDelay};
|
||||
_ThemeEqualizers = new string[] {_EqualizerChannel1, _EqualizerChannel2};
|
||||
@@ -221,47 +214,13 @@ namespace Vocaluxe.Screens
|
||||
for (int i = 0; i < CSettings.MaxNumPlayer; i++)
|
||||
CSound.AnalyzeBuffer(i);
|
||||
|
||||
if (_DelayTest != null)
|
||||
if (_DelayTest.Running)
|
||||
{
|
||||
for (int i = 0; i < _DelayTest.Length - 1; i++)
|
||||
{
|
||||
if (_DelayTestRunning && !_DelayTest[i].Timer.IsRunning)
|
||||
{
|
||||
if (CSound.GetPosition(_DelaySound) > 0f)
|
||||
{
|
||||
_DelayTest[i].Timer.Reset();
|
||||
_DelayTest[i].Timer.Start();
|
||||
}
|
||||
}
|
||||
if (_DelayTest[i].Timer.IsRunning)
|
||||
{
|
||||
int player = 0;
|
||||
if (i == 0)
|
||||
player = _SelectSlides[_SelectSlideRecordChannel1].Selection;
|
||||
|
||||
if (i == 1)
|
||||
player = _SelectSlides[_SelectSlideRecordChannel2].Selection;
|
||||
|
||||
if (_DelayTest[i].Timer.ElapsedMilliseconds > _MaxDelayTime * 1000f || player == 0)
|
||||
{
|
||||
_DelayTest[i].Delay = 0f;
|
||||
_DelayTest[i].Timer.Stop();
|
||||
_DelayTestRunning = false;
|
||||
}
|
||||
else if (CSound.RecordGetMaxVolume(player - 1) > 0.1f &&
|
||||
(CSound.RecordGetToneAbs(player - 1) == 9 || CSound.RecordGetToneAbs(player - 1) == 21 || CSound.RecordGetToneAbs(player - 1) == 33))
|
||||
{
|
||||
_DelayTest[i].Delay = _DelayTest[i].Timer.ElapsedMilliseconds;
|
||||
_DelayTest[i].Timer.Stop();
|
||||
_DelayTestRunning = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
_Texts[_TextDelayChannel1].Text = _DelayTest[0].Delay.ToString("000") + " ms";
|
||||
_Texts[_TextDelayChannel2].Text = _DelayTest[1].Delay.ToString("000") + " ms";
|
||||
_DelayTest.Update();
|
||||
_Texts[_TextDelayChannel1].Text = (_DelayTest.Delays[0] == 0) ? "???" : _DelayTest.Delays[0].ToString("000") + " ms";
|
||||
_Texts[_TextDelayChannel2].Text = (_DelayTest.Delays[1] == 0) ? "???" : _DelayTest.Delays[1].ToString("000") + " ms";
|
||||
}
|
||||
|
||||
|
||||
if (_CheckMicConfig())
|
||||
{
|
||||
_ChannelEnergy[0] = 0f;
|
||||
@@ -325,21 +284,9 @@ namespace Vocaluxe.Screens
|
||||
_Statics[_StaticWarning].Visible = false;
|
||||
_Texts[_TextWarning].Visible = false;
|
||||
|
||||
_DelayTest = null;
|
||||
if (_Devices != null)
|
||||
{
|
||||
_DelayTest = new SDelayTest[2];
|
||||
for (int i = 0; i < _DelayTest.Length - 1; i++)
|
||||
{
|
||||
_DelayTest[i].Timer = new Stopwatch();
|
||||
_DelayTest[i].Delay = 0f;
|
||||
}
|
||||
}
|
||||
_DelayTest.Reset();
|
||||
|
||||
_SelectSlides[_SelectSlideDelay].Selection = CConfig.MicDelay / 20;
|
||||
|
||||
_DelayTestRunning = false;
|
||||
_DelaySound = -1;
|
||||
}
|
||||
|
||||
public override void OnShowFinish()
|
||||
@@ -391,7 +338,7 @@ namespace Vocaluxe.Screens
|
||||
base.OnClose();
|
||||
CSound.RecordStop();
|
||||
|
||||
_DelayTest = null;
|
||||
_DelayTest.Reset();
|
||||
CBackgroundMusic.Disabled = false;
|
||||
}
|
||||
|
||||
@@ -444,6 +391,12 @@ namespace Vocaluxe.Screens
|
||||
CSound.RecordStart();
|
||||
}
|
||||
|
||||
private void _SetPlayerColors()
|
||||
{
|
||||
_Texts[_TextChannel1].Color = CTheme.GetPlayerColor(_SelectSlides[_SelectSlideRecordChannel1].Selection);
|
||||
_Texts[_TextChannel2].Color = CTheme.GetPlayerColor(_SelectSlides[_SelectSlideRecordChannel2].Selection);
|
||||
}
|
||||
|
||||
private void _SetMicConfig()
|
||||
{
|
||||
if (_DeviceNr < 0)
|
||||
@@ -451,6 +404,7 @@ namespace Vocaluxe.Screens
|
||||
CRecordDevice device = _Devices[_DeviceNr];
|
||||
device.PlayerChannel1 = _SelectSlides[_SelectSlideRecordChannel1].Selection;
|
||||
device.PlayerChannel2 = _SelectSlides[_SelectSlideRecordChannel2].Selection;
|
||||
_SetPlayerColors();
|
||||
}
|
||||
|
||||
private void _UpdateChannels()
|
||||
@@ -459,6 +413,7 @@ namespace Vocaluxe.Screens
|
||||
_SelectSlides[_SelectSlideRecordChannel2].Selection = _Devices[_DeviceNr].PlayerChannel2;
|
||||
|
||||
_SaveMicConfig();
|
||||
_SetPlayerColors();
|
||||
}
|
||||
|
||||
private bool _CheckMicConfig()
|
||||
@@ -494,12 +449,8 @@ namespace Vocaluxe.Screens
|
||||
private void _TestDelay()
|
||||
{
|
||||
_SaveMicConfig();
|
||||
|
||||
if (_DelayTest == null)
|
||||
return;
|
||||
|
||||
_DelaySound = CSound.PlaySound(ESounds.T440);
|
||||
_DelayTestRunning = true;
|
||||
_DelayTest.Reset();
|
||||
_DelayTest.Start(new int[] {_SelectSlides[_SelectSlideRecordChannel1].Selection - 1, _SelectSlides[_SelectSlideRecordChannel2].Selection - 1});
|
||||
}
|
||||
|
||||
private void _GetFirstConfiguredRecordDevice(ref int device)
|
||||
|
||||
@@ -15,12 +15,10 @@
|
||||
// along with Vocaluxe. If not, see <http://www.gnu.org/licenses/>.
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Windows.Forms;
|
||||
using Vocaluxe.Base;
|
||||
using VocaluxeLib;
|
||||
using VocaluxeLib.Menu;
|
||||
using VocaluxeLib.Draw;
|
||||
|
||||
namespace Vocaluxe.Screens
|
||||
{
|
||||
|
||||
@@ -124,7 +124,8 @@ namespace Vocaluxe.Screens
|
||||
public override void OnShow()
|
||||
{
|
||||
base.OnShow();
|
||||
_Round = CGame.NumRounds > 1 ? 0 : 1;
|
||||
//-1 --> Show average
|
||||
_Round = CGame.NumRounds > 1 ? -1 : 0;
|
||||
_Points = CGame.GetPoints();
|
||||
|
||||
_SavePlayedSongs();
|
||||
@@ -137,8 +138,8 @@ namespace Vocaluxe.Screens
|
||||
public override bool UpdateGame()
|
||||
{
|
||||
var players = new SPlayer[CGame.NumPlayer];
|
||||
if (_Round != 0)
|
||||
players = _Points.GetPlayer(_Round - 1, CGame.NumPlayer);
|
||||
if (_Round >= 0)
|
||||
players = _Points.GetPlayer(_Round, CGame.NumPlayer);
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < CGame.NumRounds; i++)
|
||||
@@ -186,8 +187,8 @@ namespace Vocaluxe.Screens
|
||||
if (_SlideShowBGAvailable)
|
||||
_SlideShowBG.Draw();
|
||||
else
|
||||
base._DrawBG();
|
||||
base._DrawFG();
|
||||
_DrawBG();
|
||||
_DrawFG();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -274,7 +275,7 @@ namespace Vocaluxe.Screens
|
||||
{
|
||||
CSong song = null;
|
||||
var players = new SPlayer[CGame.NumPlayer];
|
||||
if (_Round != 0)
|
||||
if (_Round >= 0)
|
||||
{
|
||||
song = CGame.GetSong(_Round);
|
||||
if (song == null)
|
||||
@@ -282,8 +283,8 @@ namespace Vocaluxe.Screens
|
||||
|
||||
_Texts[_TextSong].Text = song.Artist + " - " + song.Title;
|
||||
if (_Points.NumRounds > 1)
|
||||
_Texts[_TextSong].Text += " (" + _Round + "/" + _Points.NumRounds + ")";
|
||||
players = _Points.GetPlayer(_Round - 1, CGame.NumPlayer);
|
||||
_Texts[_TextSong].Text += " (" + (_Round + 1) + "/" + _Points.NumRounds + ")";
|
||||
players = _Points.GetPlayer(_Round, CGame.NumPlayer);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -395,16 +396,14 @@ namespace Vocaluxe.Screens
|
||||
|
||||
private void _ChangeRound(int num)
|
||||
{
|
||||
if ((_Round + num) <= _Points.NumRounds && (_Round + num > 0))
|
||||
{
|
||||
_Round += num;
|
||||
_UpdateRatings();
|
||||
}
|
||||
else if (num < 0 && _Round == 1 && CGame.NumRounds > 1)
|
||||
{
|
||||
_Round = 0;
|
||||
_UpdateRatings();
|
||||
}
|
||||
if (_Points.NumRounds < 1)
|
||||
return;
|
||||
_Round += num;
|
||||
_Round = _Round.Clamp(-1, _Points.NumRounds - 1);
|
||||
if (_Round >= _Points.NumRounds)
|
||||
_Round = _Points.NumRounds - 1;
|
||||
|
||||
_UpdateRatings();
|
||||
}
|
||||
|
||||
private void _SavePlayedSongs()
|
||||
@@ -429,7 +428,7 @@ namespace Vocaluxe.Screens
|
||||
|
||||
private bool _UpdateBackground()
|
||||
{
|
||||
string[] photos = CVocaluxeServer.getPhotosOfThisRound();
|
||||
string[] photos = CVocaluxeServer.GetPhotosOfThisRound();
|
||||
_SlideShowBG.RemoveSlideShowTextures();
|
||||
foreach (string photo in photos)
|
||||
_SlideShowBG.AddSlideShowTexture(photo);
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace Vocaluxe.SongQueue
|
||||
class CSongQueue : ISongQueue
|
||||
{
|
||||
private List<SSongQueueEntry> _SongQueue;
|
||||
private int _CurrentSong;
|
||||
private int _CurrentRound;
|
||||
private CPoints _Points;
|
||||
|
||||
#region Implementation
|
||||
@@ -52,9 +52,7 @@ namespace Vocaluxe.SongQueue
|
||||
|
||||
public EGameMode GetCurrentGameMode()
|
||||
{
|
||||
if (_CurrentSong >= 0 && _CurrentSong < _SongQueue.Count)
|
||||
return _SongQueue[_CurrentSong].GameMode;
|
||||
return EGameMode.TR_GAMEMODE_NORMAL;
|
||||
return GetGameMode(_CurrentRound);
|
||||
}
|
||||
|
||||
public bool AddVisibleSong(int visibleIndex, EGameMode gameMode)
|
||||
@@ -105,7 +103,7 @@ namespace Vocaluxe.SongQueue
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_CurrentSong = -1;
|
||||
_CurrentRound = -1;
|
||||
}
|
||||
|
||||
public void Start(SPlayer[] players)
|
||||
@@ -113,39 +111,51 @@ namespace Vocaluxe.SongQueue
|
||||
_Points = new CPoints(_SongQueue.Count, players);
|
||||
}
|
||||
|
||||
public void NextRound(SPlayer[] players)
|
||||
public void StartNextRound(SPlayer[] players)
|
||||
{
|
||||
if (_CurrentSong < _SongQueue.Count && _SongQueue.Count > 0)
|
||||
if (IsFinished())
|
||||
return;
|
||||
if (_CurrentRound > -1)
|
||||
{
|
||||
if (_CurrentSong > -1)
|
||||
{
|
||||
_Points.SetPoints(
|
||||
_CurrentSong,
|
||||
_SongQueue[_CurrentSong].SongID,
|
||||
players,
|
||||
_SongQueue[_CurrentSong].GameMode == EGameMode.TR_GAMEMODE_MEDLEY,
|
||||
_SongQueue[_CurrentSong].GameMode == EGameMode.TR_GAMEMODE_DUET,
|
||||
_SongQueue[_CurrentSong].GameMode == EGameMode.TR_GAMEMODE_SHORTSONG);
|
||||
}
|
||||
_CurrentSong++;
|
||||
_Points.SetPoints(
|
||||
_CurrentRound,
|
||||
_SongQueue[_CurrentRound].SongID,
|
||||
players,
|
||||
_SongQueue[_CurrentRound].GameMode);
|
||||
}
|
||||
_CurrentRound++;
|
||||
}
|
||||
|
||||
public bool IsFinished()
|
||||
{
|
||||
return _CurrentSong == _SongQueue.Count || _SongQueue.Count == 0;
|
||||
return _CurrentRound >= _SongQueue.Count || _SongQueue.Count == 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get current round nr (1 ~ n)
|
||||
/// </summary>
|
||||
/// <returns>current round nr (1 ~ n)</returns>
|
||||
public int GetCurrentRoundNr()
|
||||
{
|
||||
return _CurrentSong + 1;
|
||||
return _CurrentRound + 1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns current round
|
||||
/// </summary>
|
||||
/// <returns>Current round (0 based)</returns>
|
||||
public int GetCurrentRound()
|
||||
{
|
||||
return _CurrentRound;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get current song
|
||||
/// </summary>
|
||||
/// <returns>Song of current round or null if there is none/game finished</returns>
|
||||
public CSong GetSong()
|
||||
{
|
||||
if (_CurrentSong >= 0 && _CurrentSong < _SongQueue.Count)
|
||||
return CGameModes.Get(_SongQueue[_CurrentSong].GameMode).GetSong(_SongQueue[_CurrentSong].SongID);
|
||||
return null;
|
||||
return GetSong(_CurrentRound);
|
||||
}
|
||||
|
||||
public int GetNumSongs()
|
||||
@@ -153,18 +163,28 @@ namespace Vocaluxe.SongQueue
|
||||
return _SongQueue.Count;
|
||||
}
|
||||
|
||||
public CSong GetSong(int num)
|
||||
/// <summary>
|
||||
/// Get song of specified round
|
||||
/// </summary>
|
||||
/// <param name="round">Round (0 based)</param>
|
||||
/// <returns>Current song or null if out of bounds</returns>
|
||||
public CSong GetSong(int round)
|
||||
{
|
||||
if (num - 1 < _SongQueue.Count && num > 0)
|
||||
return CSongs.GetSong(_SongQueue[num - 1].SongID);
|
||||
if (round < _SongQueue.Count && round >= 0)
|
||||
return CSongs.GetSong(_SongQueue[round].SongID);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public EGameMode GetGameMode(int num)
|
||||
/// <summary>
|
||||
/// Get gameMode of specified round
|
||||
/// </summary>
|
||||
/// <param name="round">Round (0 based)</param>
|
||||
/// <returns>Current song or null if out of bounds</returns>
|
||||
public EGameMode GetGameMode(int round)
|
||||
{
|
||||
if (num - 1 < _SongQueue.Count && num > 0)
|
||||
return _SongQueue[num - 1].GameMode;
|
||||
if (round < _SongQueue.Count && round >= 0)
|
||||
return _SongQueue[round].GameMode;
|
||||
|
||||
return EGameMode.TR_GAMEMODE_NORMAL;
|
||||
}
|
||||
|
||||
@@ -25,8 +25,6 @@ namespace Vocaluxe.SongQueue
|
||||
{
|
||||
void Init();
|
||||
|
||||
EGameMode GetCurrentGameMode();
|
||||
|
||||
bool AddVisibleSong(int visibleIndex, EGameMode gameMode);
|
||||
bool AddSong(int absoluteIndex, EGameMode gameMode);
|
||||
bool RemoveVisibleSong(int visibleIndex);
|
||||
@@ -35,15 +33,17 @@ namespace Vocaluxe.SongQueue
|
||||
|
||||
void Reset();
|
||||
void Start(SPlayer[] players);
|
||||
void NextRound(SPlayer[] players);
|
||||
void StartNextRound(SPlayer[] players);
|
||||
bool IsFinished();
|
||||
int GetCurrentRoundNr();
|
||||
|
||||
CPoints GetPoints();
|
||||
|
||||
int GetNumSongs();
|
||||
int GetCurrentRoundNr();
|
||||
|
||||
CSong GetSong();
|
||||
CSong GetSong(int num);
|
||||
EGameMode GetGameMode(int num);
|
||||
CSong GetSong(int round);
|
||||
EGameMode GetCurrentGameMode();
|
||||
EGameMode GetGameMode(int round);
|
||||
}
|
||||
}
|
||||
@@ -212,11 +212,14 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Base\CBackgroundMusic.cs" />
|
||||
<Compile Include="Lib\Sound\CBuffer.cs" />
|
||||
<Compile Include="Base\CConfig.cs" />
|
||||
<Compile Include="Base\CCover.cs" />
|
||||
<Compile Include="Base\CCursor.cs" />
|
||||
<Compile Include="Base\CDataBase.cs" />
|
||||
<Compile Include="Base\CDraw.cs" />
|
||||
<Compile Include="Lib\Sound\CPt1.cs" />
|
||||
<Compile Include="Lib\Sound\CSyncTimer.cs" />
|
||||
<Compile Include="Base\Fonts\CFont.cs" />
|
||||
<Compile Include="Base\CGame.cs" />
|
||||
<Compile Include="Base\CController.cs" />
|
||||
@@ -251,7 +254,9 @@
|
||||
<Compile Include="Lib\Input\CControllerFramework.cs" />
|
||||
<Compile Include="Lib\Sound\CGstreamerSharpAudio.cs" />
|
||||
<Compile Include="Lib\Video\Acinerella\CDecoder.cs" />
|
||||
<Compile Include="Lib\Video\Acinerella\CDecoderThread.cs" />
|
||||
<Compile Include="Lib\Video\Acinerella\CFramebuffer.cs" />
|
||||
<Compile Include="Lib\Sound\CDelayTest.cs" />
|
||||
<Compile Include="Screens\CPopupScreenServerQR.cs" />
|
||||
<Compile Include="Screens\CScreenOptionsVideoAdjustments.cs" />
|
||||
<Compile Include="SongQueue\CSongQueue.cs" />
|
||||
@@ -484,4 +489,4 @@
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
</Project>
|
||||
@@ -22,6 +22,7 @@
|
||||
position: relative;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
background-color: #000000;
|
||||
background-color: rgba(0,0,0,0.7);
|
||||
}
|
||||
|
||||
@@ -30,6 +31,7 @@
|
||||
height: 100%;
|
||||
top: 0;
|
||||
margin: 0;
|
||||
background: #000000;
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
display: none;
|
||||
position: fixed;
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
#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.Diagnostics;
|
||||
|
||||
namespace VocaluxeLib
|
||||
{
|
||||
public class CFading
|
||||
{
|
||||
private readonly float _FromValue;
|
||||
private readonly float _ToValue;
|
||||
private readonly float _Duration; //in ms
|
||||
private readonly Stopwatch _Timer = new Stopwatch();
|
||||
|
||||
/// <summary>
|
||||
/// Starts a fading process adjusting between 2 values over a given amount of time
|
||||
/// </summary>
|
||||
/// <param name="fromValue">Start value</param>
|
||||
/// <param name="toValue">Target value</param>
|
||||
/// <param name="duration">Duration of the fading in seconds</param>
|
||||
public CFading(float fromValue, float toValue, float duration)
|
||||
{
|
||||
if (duration < 0)
|
||||
duration = 0;
|
||||
_FromValue = fromValue;
|
||||
_ToValue = toValue;
|
||||
_Duration = duration * 1000f;
|
||||
_Timer.Start();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current value and sets finished
|
||||
/// </summary>
|
||||
/// <param name="finished">Set to whether fading has finished</param>
|
||||
/// <returns>Current value (between from and to values)</returns>
|
||||
public float GetValue(out bool finished)
|
||||
{
|
||||
float result;
|
||||
if (_Timer.ElapsedMilliseconds < _Duration)
|
||||
{
|
||||
result = (_Timer.ElapsedMilliseconds / _Duration) * (_ToValue - _FromValue) + _FromValue;
|
||||
finished = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = _ToValue;
|
||||
finished = true;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -47,6 +47,15 @@ namespace VocaluxeLib
|
||||
return (int)result;
|
||||
}
|
||||
|
||||
public static T Clamp<T>(this T val, T min, T max) where T : IComparable<T>
|
||||
{
|
||||
if (val.CompareTo(min) < 0)
|
||||
return min;
|
||||
if (val.CompareTo(max) > 0)
|
||||
return max;
|
||||
return val;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Concat strings into one string with ", " as separator.
|
||||
/// </summary>
|
||||
|
||||
@@ -355,6 +355,7 @@ namespace VocaluxeLib
|
||||
[Flags]
|
||||
public enum EUserRole
|
||||
{
|
||||
// ReSharper disable InconsistentNaming
|
||||
TR_USERROLE_GUEST = 0,
|
||||
TR_USERROLE_NORMAL = 1,
|
||||
TR_USERROLE_ADMIN = 2,
|
||||
@@ -362,5 +363,6 @@ namespace VocaluxeLib
|
||||
TR_USERROLE_ADDSONGSUSER = 8,
|
||||
TR_USERROLE_PLAYLISTEDITOR = 16,
|
||||
TR_USERROLE_PROFILEEDITOR = 32
|
||||
// ReSharper restore InconsistentNaming
|
||||
}
|
||||
}
|
||||
@@ -19,11 +19,10 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace VocaluxeLib
|
||||
{
|
||||
public static class Extensions
|
||||
public static class CExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Resizes the given list to the given size. Removes elements or adds default values
|
||||
|
||||
@@ -35,15 +35,13 @@ namespace VocaluxeLib.Game
|
||||
_Rounds[round, player].Points = 0f;
|
||||
_Rounds[round, player].PointsGoldenNotes = 0f;
|
||||
_Rounds[round, player].PointsLineBonus = 0f;
|
||||
_Rounds[round, player].Medley = false;
|
||||
_Rounds[round, player].Duet = false;
|
||||
_Rounds[round, player].ShortSong = false;
|
||||
_Rounds[round, player].GameMode = EGameMode.TR_GAMEMODE_NORMAL;
|
||||
_Rounds[round, player].SongFinished = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SetPoints(int round, int songID, SPlayer[] players, bool medley, bool duet, bool shortSong)
|
||||
public void SetPoints(int round, int songID, SPlayer[] players, EGameMode gameMode)
|
||||
{
|
||||
long dateTicks = DateTime.Now.Ticks;
|
||||
for (int player = 0; player < players.Length; player++)
|
||||
@@ -53,9 +51,7 @@ namespace VocaluxeLib.Game
|
||||
_Rounds[round, player].Points = players[player].Points;
|
||||
_Rounds[round, player].PointsGoldenNotes = players[player].PointsGoldenNotes;
|
||||
_Rounds[round, player].PointsLineBonus = players[player].PointsLineBonus;
|
||||
_Rounds[round, player].Medley = medley;
|
||||
_Rounds[round, player].Duet = duet;
|
||||
_Rounds[round, player].ShortSong = shortSong;
|
||||
_Rounds[round, player].GameMode = gameMode;
|
||||
_Rounds[round, player].DateTicks = dateTicks;
|
||||
_Rounds[round, player].SongFinished = players[player].SongFinished;
|
||||
}
|
||||
@@ -87,9 +83,7 @@ namespace VocaluxeLib.Game
|
||||
players[p].PointsLineBonus = _Rounds[round, p].PointsLineBonus;
|
||||
players[p].SongID = _Rounds[round, p].SongID;
|
||||
players[p].VoiceNr = _Rounds[round, p].VoiceNr;
|
||||
players[p].Medley = _Rounds[round, p].Medley;
|
||||
players[p].Duet = _Rounds[round, p].Duet;
|
||||
players[p].ShortSong = _Rounds[round, p].ShortSong;
|
||||
players[p].GameMode = _Rounds[round, p].GameMode;
|
||||
players[p].DateTicks = _Rounds[round, p].DateTicks;
|
||||
players[p].SongFinished = _Rounds[round, p].SongFinished;
|
||||
players[p].ProfileID = _Rounds[round, p].ProfileID;
|
||||
|
||||
@@ -155,6 +155,8 @@ namespace VocaluxeLib
|
||||
public interface ILog
|
||||
{
|
||||
void LogError(string errorText);
|
||||
void LogDebug(string text);
|
||||
void LogSongInfo(string text);
|
||||
}
|
||||
|
||||
public interface IFonts
|
||||
|
||||
@@ -54,8 +54,8 @@ namespace VocaluxeLib.Menu
|
||||
private bool _ThemeLoaded;
|
||||
|
||||
private int _SlideShowCurrent;
|
||||
private Stopwatch _SlideShowTimer = new Stopwatch();
|
||||
private List<CTexture> _SlideShowTextures = new List<CTexture>();
|
||||
private readonly Stopwatch _SlideShowTimer = new Stopwatch();
|
||||
private readonly List<CTexture> _SlideShowTextures = new List<CTexture>();
|
||||
|
||||
public SColorF Color;
|
||||
|
||||
@@ -69,8 +69,7 @@ namespace VocaluxeLib.Menu
|
||||
{
|
||||
_PartyModeID = partyModeID;
|
||||
_ThemeLoaded = false;
|
||||
_Theme = new SThemeBackground();
|
||||
_Theme.SlideShowTextures = new List<string>();
|
||||
_Theme = new SThemeBackground {SlideShowTextures = new List<string>()};
|
||||
|
||||
Color = new SColorF(0f, 0f, 0f, 1f);
|
||||
}
|
||||
@@ -102,11 +101,11 @@ namespace VocaluxeLib.Menu
|
||||
_ThemeLoaded &= success;
|
||||
}
|
||||
|
||||
string slideShow = "";
|
||||
int i = 1;
|
||||
|
||||
while (xmlReader.ItemExists(item + "/SlideShow" + i))
|
||||
{
|
||||
string slideShow;
|
||||
xmlReader.GetValue(item + "/SlideShow" + i, out slideShow, String.Empty);
|
||||
if (slideShow != "")
|
||||
_Theme.SlideShowTextures.Add(slideShow);
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Xml;
|
||||
using VocaluxeLib.Songs;
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
using System.Xml;
|
||||
using VocaluxeLib.Draw;
|
||||
|
||||
@@ -15,11 +15,8 @@
|
||||
// along with Vocaluxe. If not, see <http://www.gnu.org/licenses/>.
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using VocaluxeLib.PartyModes;
|
||||
using VocaluxeLib.Draw;
|
||||
using VocaluxeLib.Profile;
|
||||
|
||||
@@ -94,10 +91,7 @@ namespace VocaluxeLib.Menu
|
||||
_NumPlayer = numPlayer;
|
||||
_NumPlayerTeams = numPlayerTeams;
|
||||
|
||||
if (_NumTeams > 0)
|
||||
_TeamList = new List<int>[_NumTeams];
|
||||
else
|
||||
_TeamList = new List<int>[1];
|
||||
_TeamList = new List<int>[_NumTeams > 0 ? _NumTeams : 1];
|
||||
|
||||
if (_NumTeams != _NumPlayerTeams.Length)
|
||||
_NumPlayerTeams = new int[_NumTeams];
|
||||
@@ -126,7 +120,7 @@ namespace VocaluxeLib.Menu
|
||||
{
|
||||
//Handle left/right/up/down
|
||||
_NameSelections[_NameSelection].HandleInput(keyEvent);
|
||||
int numberPressed = -1;
|
||||
int numPressed = -1;
|
||||
bool resetSelection = false;
|
||||
switch (keyEvent.Key)
|
||||
{
|
||||
@@ -157,20 +151,65 @@ namespace VocaluxeLib.Menu
|
||||
case Keys.Back:
|
||||
resetSelection = true;
|
||||
break;
|
||||
|
||||
case Keys.D1:
|
||||
case Keys.NumPad1:
|
||||
numPressed = 1;
|
||||
break;
|
||||
|
||||
case Keys.D2:
|
||||
case Keys.NumPad2:
|
||||
numPressed = 2;
|
||||
break;
|
||||
|
||||
case Keys.D3:
|
||||
case Keys.NumPad3:
|
||||
numPressed = 3;
|
||||
break;
|
||||
|
||||
case Keys.D4:
|
||||
case Keys.NumPad4:
|
||||
numPressed = 4;
|
||||
break;
|
||||
|
||||
case Keys.D5:
|
||||
case Keys.NumPad5:
|
||||
numPressed = 5;
|
||||
break;
|
||||
|
||||
case Keys.D6:
|
||||
case Keys.NumPad6:
|
||||
numPressed = 6;
|
||||
break;
|
||||
|
||||
case Keys.D7:
|
||||
case Keys.NumPad7:
|
||||
numPressed = 7;
|
||||
break;
|
||||
|
||||
case Keys.D8:
|
||||
case Keys.NumPad8:
|
||||
numPressed = 8;
|
||||
break;
|
||||
|
||||
case Keys.D9:
|
||||
case Keys.NumPad9:
|
||||
numPressed = 9;
|
||||
break;
|
||||
}
|
||||
if (numberPressed > 0 || resetSelection)
|
||||
if (numPressed > 0 || resetSelection)
|
||||
{
|
||||
if (numberPressed == _SelectingFastPlayerNr || resetSelection)
|
||||
if (numPressed == _SelectingFastPlayerNr || resetSelection)
|
||||
{
|
||||
//Reset all values
|
||||
_SelectingFastPlayerNr = 0;
|
||||
_SelectingKeyboardActive = false;
|
||||
_NameSelections[_NameSelection].FastSelection(false, -1);
|
||||
}
|
||||
else if (numberPressed <= _NumPlayerTeams[_CurrentTeam])
|
||||
else if (numPressed <= _NumPlayerTeams[_CurrentTeam])
|
||||
{
|
||||
_SelectingFastPlayerNr = numberPressed;
|
||||
_NameSelections[_NameSelection].FastSelection(true, numberPressed);
|
||||
_SelectingFastPlayerNr = numPressed;
|
||||
_NameSelections[_NameSelection].FastSelection(true, numPressed);
|
||||
}
|
||||
_SelectingFast = false;
|
||||
}
|
||||
@@ -530,9 +569,7 @@ namespace VocaluxeLib.Menu
|
||||
|
||||
public SPartyNameOptions GetData()
|
||||
{
|
||||
SPartyNameOptions option = new SPartyNameOptions();
|
||||
option.NumPlayerTeams = _NumPlayerTeams;
|
||||
option.TeamList = _TeamList;
|
||||
SPartyNameOptions option = new SPartyNameOptions {NumPlayerTeams = _NumPlayerTeams, TeamList = _TeamList};
|
||||
return option;
|
||||
}
|
||||
|
||||
@@ -692,7 +729,7 @@ namespace VocaluxeLib.Menu
|
||||
{
|
||||
if (_NumPlayerTeams[team] == _TeamList[team].Count && !_ChangePlayerNumDynamic)
|
||||
return;
|
||||
else if (_NumPlayerTeams[team] == _PartyMode.GetMaxPlayerPerTeam())
|
||||
if (_NumPlayerTeams[team] == _PartyMode.GetMaxPlayerPerTeam())
|
||||
return;
|
||||
|
||||
_NameSelections[_NameSelection].UseProfile(profileID);
|
||||
@@ -707,8 +744,8 @@ namespace VocaluxeLib.Menu
|
||||
{
|
||||
List<int> ids = new List<int>();
|
||||
ids.AddRange(_TeamList[t]);
|
||||
for (int p = 0; p < ids.Count; p++)
|
||||
_RemovePlayer(t, ids[p]);
|
||||
foreach (int id in ids)
|
||||
_RemovePlayer(t, id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -94,7 +94,7 @@ namespace VocaluxeLib.Menu
|
||||
private int _Player = -1;
|
||||
|
||||
private readonly List<int> _VisibleProfiles;
|
||||
private List<int> _UsedProfiles;
|
||||
private readonly List<int> _UsedProfiles;
|
||||
|
||||
private CStatic _PlayerSelector;
|
||||
|
||||
@@ -416,7 +416,6 @@ namespace VocaluxeLib.Menu
|
||||
_Tiles[i].Avatar.Texture = CBase.Profiles.GetAvatar(_VisibleProfiles[i + offset * _Tiles.Count]);
|
||||
_Tiles[i].Avatar.Color = new SColorF(1, 1, 1, 1);
|
||||
_Tiles[i].Name.Text = CBase.Profiles.GetPlayerName(_VisibleProfiles[i + offset * _Tiles.Count]);
|
||||
;
|
||||
_Tiles[i].ProfileID = _VisibleProfiles[i + offset * _Tiles.Count];
|
||||
}
|
||||
else
|
||||
|
||||
@@ -214,7 +214,8 @@ namespace VocaluxeLib.Menu.SongMenu
|
||||
if (_SongMenu != null)
|
||||
_SongMenu.OnHide();
|
||||
|
||||
switch (CBase.Config.GetSongMenuType())
|
||||
_Type = CBase.Config.GetSongMenuType();
|
||||
switch (_Type)
|
||||
{
|
||||
//case ESongMenu.TR_CONFIG_LIST:
|
||||
// _SongMenu = new CSongMenuList();
|
||||
@@ -231,8 +232,6 @@ namespace VocaluxeLib.Menu.SongMenu
|
||||
// _SongMenu = new CSongMenuBook();
|
||||
// break;
|
||||
}
|
||||
|
||||
_Type = CBase.Config.GetSongMenuType();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,6 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
using VocaluxeLib.Draw;
|
||||
@@ -99,7 +98,7 @@ namespace VocaluxeLib.Menu.SongMenu
|
||||
protected SThemeSongMenu _Theme;
|
||||
private bool _ThemeLoaded;
|
||||
|
||||
private readonly Stopwatch _VideoFadeTimer = new Stopwatch();
|
||||
private CFading _VideoFading;
|
||||
private readonly List<int> _Streams = new List<int>();
|
||||
protected CTexture _Vidtex;
|
||||
|
||||
@@ -388,12 +387,12 @@ namespace VocaluxeLib.Menu.SongMenu
|
||||
{
|
||||
if (_Vidtex != null)
|
||||
{
|
||||
if (_VideoFadeTimer.ElapsedMilliseconds <= 3000L)
|
||||
_Vidtex.Color.A = _VideoFadeTimer.ElapsedMilliseconds / 3000f;
|
||||
else
|
||||
if (_VideoFading != null)
|
||||
{
|
||||
_Vidtex.Color.A = 1f;
|
||||
_VideoFadeTimer.Stop();
|
||||
bool finished;
|
||||
_Vidtex.Color.A = _VideoFading.GetValue(out finished);
|
||||
if (finished)
|
||||
_VideoFading = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -563,9 +562,7 @@ namespace VocaluxeLib.Menu.SongMenu
|
||||
if (_PreviewVideoStream == -1)
|
||||
return;
|
||||
CBase.Video.Skip(_PreviewVideoStream, startposition, song.VideoGap);
|
||||
_VideoFadeTimer.Stop();
|
||||
_VideoFadeTimer.Reset();
|
||||
_VideoFadeTimer.Start();
|
||||
_VideoFading = new CFading(0f, 1f, 3f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,11 +67,11 @@ namespace VocaluxeLib.Menu.SongMenu
|
||||
{
|
||||
set
|
||||
{
|
||||
base._PlaySong(value);
|
||||
base._PreviewIdInternal = value;
|
||||
_PlaySong(value);
|
||||
_PreviewIdInternal = value;
|
||||
_UpdatePreview();
|
||||
}
|
||||
get { return base._PreviewIdInternal; }
|
||||
get { return _PreviewIdInternal; }
|
||||
}
|
||||
|
||||
public override int GetActualSelection()
|
||||
@@ -138,7 +138,7 @@ namespace VocaluxeLib.Menu.SongMenu
|
||||
}
|
||||
|
||||
if (_Length < 0 && CBase.Sound.GetLength(_PreviewSongStream) > 0 && CBase.Songs.IsInCategory())
|
||||
UpdateLength(CBase.Songs.GetVisibleSong(_PreviewId));
|
||||
_UpdateLength(CBase.Songs.GetVisibleSong(_PreviewId));
|
||||
}
|
||||
|
||||
private void _UpdatePreview()
|
||||
@@ -181,7 +181,7 @@ namespace VocaluxeLib.Menu.SongMenu
|
||||
_MedleyCalcIcon.Visible = song.Medley.Source == EDataSource.Calculated;
|
||||
_MedleyTagIcon.Visible = song.Medley.Source == EDataSource.Tag;
|
||||
|
||||
UpdateLength(song);
|
||||
_UpdateLength(song);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -198,23 +198,22 @@ namespace VocaluxeLib.Menu.SongMenu
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateLength(CSong song)
|
||||
private void _UpdateLength(CSong song)
|
||||
{
|
||||
if (song != null)
|
||||
{
|
||||
float time = CBase.Sound.GetLength(_PreviewSongStream);
|
||||
if (Math.Abs(song.Finish) > 0.001)
|
||||
time = song.Finish;
|
||||
if (song == null)
|
||||
return;
|
||||
float time = CBase.Sound.GetLength(_PreviewSongStream);
|
||||
if (Math.Abs(song.Finish) > 0.001)
|
||||
time = song.Finish;
|
||||
|
||||
// The audiobackend is not yet ready to return the length
|
||||
if (time > 0)
|
||||
{
|
||||
time -= song.Start;
|
||||
var min = (int)Math.Floor(time / 60f);
|
||||
var sec = (int)(time - min * 60f);
|
||||
_SongLength.Text = min.ToString("00") + ":" + sec.ToString("00");
|
||||
_Length = time;
|
||||
}
|
||||
// The audiobackend is ready to return the length
|
||||
if (time > 0)
|
||||
{
|
||||
time -= song.Start;
|
||||
var min = (int)Math.Floor(time / 60f);
|
||||
var sec = (int)(time - min * 60f);
|
||||
_SongLength.Text = min.ToString("00") + ":" + sec.ToString("00");
|
||||
_Length = time;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -556,7 +555,7 @@ namespace VocaluxeLib.Menu.SongMenu
|
||||
|
||||
public override void SetSelectedSong(int visibleSongNr)
|
||||
{
|
||||
base._PlaySong(visibleSongNr);
|
||||
_PlaySong(visibleSongNr);
|
||||
base.SetSelectedSong(visibleSongNr);
|
||||
|
||||
if (visibleSongNr >= 0 && visibleSongNr < CBase.Songs.GetNumSongsVisible())
|
||||
|
||||
@@ -49,7 +49,7 @@ namespace VocaluxeLib.Profile
|
||||
CBase.Drawing.RemoveTexture(ref Texture);
|
||||
}
|
||||
|
||||
public string getFileName()
|
||||
public string GetFileName()
|
||||
{
|
||||
return FileName;
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
|
||||
namespace VocaluxeLib.Profile
|
||||
@@ -71,9 +70,11 @@ namespace VocaluxeLib.Profile
|
||||
FileName = String.Empty;
|
||||
}
|
||||
|
||||
public bool LoadProfile()
|
||||
public bool LoadProfile(string pathName, string fileName)
|
||||
{
|
||||
return LoadProfile(FilePath, FileName);
|
||||
FilePath = pathName;
|
||||
FileName = fileName;
|
||||
return LoadProfile();
|
||||
}
|
||||
|
||||
public bool LoadProfile(string file)
|
||||
@@ -81,10 +82,10 @@ namespace VocaluxeLib.Profile
|
||||
FileName = Path.GetFileName(file);
|
||||
FilePath = Path.GetDirectoryName(file);
|
||||
|
||||
return LoadProfile(FilePath, FileName);
|
||||
return LoadProfile();
|
||||
}
|
||||
|
||||
public bool LoadProfile(string pathName, string fileName)
|
||||
public bool LoadProfile()
|
||||
{
|
||||
CXMLReader xmlReader = CXMLReader.OpenFile(Path.Combine(FilePath, FileName));
|
||||
if (xmlReader == null)
|
||||
|
||||
@@ -63,15 +63,10 @@ namespace VocaluxeLib.Songs
|
||||
{
|
||||
get
|
||||
{
|
||||
int min = int.MaxValue;
|
||||
int max = int.MinValue;
|
||||
foreach (T note in _Notes)
|
||||
{
|
||||
if (note.Tone < min)
|
||||
min = note.Tone;
|
||||
if (note.Tone > max)
|
||||
max = note.Tone;
|
||||
}
|
||||
if (_Notes.Count == 0)
|
||||
return 0;
|
||||
int min = _Notes.Min(note => note.Tone);
|
||||
int max = _Notes.Max(note => note.Tone);
|
||||
|
||||
return min - (max - min) / 4;
|
||||
}
|
||||
@@ -140,11 +135,10 @@ namespace VocaluxeLib.Songs
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool IncLastNoteLength()
|
||||
public void IncLastNoteLength()
|
||||
{
|
||||
if (_Notes.Count > 0)
|
||||
_Notes[NoteCount - 1].Duration++;
|
||||
return false;
|
||||
}
|
||||
|
||||
public void DeleteAllNotes()
|
||||
|
||||
@@ -97,7 +97,7 @@ namespace VocaluxeLib.Songs
|
||||
|
||||
public string MP3FileName = String.Empty;
|
||||
public string CoverFileName = String.Empty;
|
||||
public List<string> BackgroundFileNames = new List<string>();
|
||||
public readonly List<string> BackgroundFileNames = new List<string>();
|
||||
public string VideoFileName = String.Empty;
|
||||
|
||||
public EAspect VideoAspect = EAspect.Crop;
|
||||
|
||||
@@ -81,7 +81,7 @@ namespace VocaluxeLib.Songs
|
||||
msg = (error ? "Error: " : "Warning: ") + msg;
|
||||
if (withLineNr)
|
||||
msg += " in line #" + _LineNr;
|
||||
CBase.Log.LogError(msg + " (" + Path.Combine(_Song.Folder, _Song.FileName) + ")");
|
||||
CBase.Log.LogSongInfo(msg + " (" + Path.Combine(_Song.Folder, _Song.FileName) + ")");
|
||||
}
|
||||
|
||||
private void _LogError(string msg, bool withLineNr = true)
|
||||
|
||||
@@ -41,6 +41,7 @@ namespace VocaluxeLib.Songs
|
||||
/// <param name="duration"></param>
|
||||
/// <param name="tone"></param>
|
||||
/// <param name="hitNote"></param>
|
||||
/// <param name="points"></param>
|
||||
public CSungNote(int startBeat, int duration, int tone, CSongNote hitNote, double points) : this(startBeat, duration, tone)
|
||||
{
|
||||
HitNote = hitNote;
|
||||
|
||||
@@ -205,15 +205,13 @@ namespace VocaluxeLib.Songs
|
||||
|
||||
public void UpdateTimings()
|
||||
{
|
||||
CSongNote lastNote;
|
||||
|
||||
if (_Lines.Count == 0)
|
||||
return;
|
||||
_Lines[0].StartBeat = -10000;
|
||||
|
||||
for (int i = 1; i < _Lines.Count; i++)
|
||||
{
|
||||
lastNote = _Lines[i - 1].LastNote;
|
||||
CSongNote lastNote = _Lines[i - 1].LastNote;
|
||||
CSongNote firstNote = _Lines[i].FirstNote;
|
||||
|
||||
if ((lastNote != null) && (firstNote != null))
|
||||
|
||||
@@ -190,20 +190,18 @@ namespace VocaluxeLib
|
||||
public int CurrentNote;
|
||||
|
||||
public int SongID;
|
||||
public bool Medley;
|
||||
public bool Duet;
|
||||
public bool ShortSong;
|
||||
public EGameMode GameMode;
|
||||
public long DateTicks;
|
||||
public bool SongFinished;
|
||||
}
|
||||
|
||||
public struct SScores
|
||||
public struct SDBScoreEntry
|
||||
{
|
||||
public string Name;
|
||||
public int Score;
|
||||
public string Date;
|
||||
public EGameDifficulty Difficulty;
|
||||
public int LineNr;
|
||||
public int VoiceNr;
|
||||
public int ID;
|
||||
}
|
||||
|
||||
|
||||
@@ -130,6 +130,7 @@
|
||||
<Reference Include="System.XML" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="CFading.cs" />
|
||||
<Compile Include="Extensions.cs" />
|
||||
<Compile Include="GlobalSuppressions.cs" />
|
||||
<Compile Include="IBasic.cs" />
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
// along with Vocaluxe. If not, see <http://www.gnu.org/licenses/>.
|
||||
#endregion
|
||||
|
||||
using System.Security.Authentication;
|
||||
using System.Security.Principal;
|
||||
using Security.Cryptography;
|
||||
using Security.Cryptography.X509Certificates;
|
||||
using System;
|
||||
@@ -26,34 +28,64 @@ using NetFwTypeLib;
|
||||
|
||||
namespace WebserverInitalConfig
|
||||
{
|
||||
public static class CConfigHttpApi
|
||||
public class CConfigHttpApi
|
||||
{
|
||||
// ReSharper disable InconsistentNaming
|
||||
private const String CLSID_NetFwMgr = "{304CE942-6E39-40D8-943A-B913C40C9CD4}";
|
||||
private const String CLSID_NetAuthApp = "{EC9846B3-2762-4A6B-A214-6ACB603462D2}";
|
||||
private const String CLSID_NetOpenPort = "{0CA545C6-37AD-4A6C-BF92-9F7610067EF5}";
|
||||
private const string _AppGUID = "{7baf41f1-48b7-42cb-b145-f815499cb48f}";
|
||||
// ReSharper restore InconsistentNaming
|
||||
public static void ReserveUrl(string networkString)
|
||||
|
||||
private readonly string _RuleName;
|
||||
private readonly string _ExePath;
|
||||
private readonly string _IP;
|
||||
private readonly int _Port;
|
||||
private readonly bool _IsTCP;
|
||||
|
||||
public CConfigHttpApi(string ruleName, string exePath, string ip, int port, bool isTCP)
|
||||
{
|
||||
_ExePath = exePath;
|
||||
_Port = port;
|
||||
_IsTCP = isTCP;
|
||||
_IP = ip;
|
||||
_RuleName = ruleName;
|
||||
}
|
||||
|
||||
private static void _ReserveUrl(string networkString)
|
||||
{
|
||||
if (!IsAdministrator())
|
||||
throw new AuthenticationException();
|
||||
HttpApi.ReserveURL(networkString, "D:(A;;GX;;;S-1-1-0)");
|
||||
}
|
||||
|
||||
public static void BindCert(string ip, int port, X509Certificate2 cert)
|
||||
public void ReserveUrl()
|
||||
{
|
||||
IPEndPoint endpoint = new IPEndPoint(IPAddress.Parse(ip), port);
|
||||
if (HttpApi.QuerySslCertificateInfo(endpoint) != null)
|
||||
HttpApi.DeleteCertificateBinding(endpoint);
|
||||
|
||||
HttpApi.BindCertificate(endpoint, cert.GetCertHash(), StoreName.My, new Guid("{7baf41f1-48b7-42cb-b145-f815499cb48f}"));
|
||||
_ReserveUrl("https://+:" + _Port + "/");
|
||||
}
|
||||
|
||||
public static void AddCertToStore(X509Certificate2 cert)
|
||||
private void _BindCert(X509Certificate cert)
|
||||
{
|
||||
IPEndPoint endpoint = new IPEndPoint(IPAddress.Parse(_IP), _Port);
|
||||
HttpApi.SslCertificateInfo certificateInfo = HttpApi.QuerySslCertificateInfo(endpoint);
|
||||
if (certificateInfo != null && !certificateInfo.Hash.SequenceEqual(cert.GetCertHash()))
|
||||
{
|
||||
if (!IsAdministrator())
|
||||
throw new AuthenticationException();
|
||||
HttpApi.DeleteCertificateBinding(endpoint);
|
||||
|
||||
HttpApi.BindCertificate(endpoint, cert.GetCertHash(), StoreName.My, new Guid(_AppGUID));
|
||||
}
|
||||
}
|
||||
|
||||
private static void _AddCertToStore(X509Certificate2 cert)
|
||||
{
|
||||
X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
|
||||
store.Open(OpenFlags.ReadWrite);
|
||||
|
||||
X509Certificate2Collection oldCerts = store.Certificates.Find(X509FindType.FindBySubjectDistinguishedName,
|
||||
cert.SubjectName.Name, false);
|
||||
// ReSharper disable AssignNullToNotNullAttribute
|
||||
X509Certificate2Collection oldCerts = store.Certificates.Find(X509FindType.FindBySubjectDistinguishedName, cert.SubjectName.Name, false);
|
||||
// ReSharper restore AssignNullToNotNullAttribute
|
||||
|
||||
foreach (X509Certificate2 oldCert in oldCerts)
|
||||
store.Remove(oldCert);
|
||||
@@ -62,7 +94,25 @@ namespace WebserverInitalConfig
|
||||
store.Close();
|
||||
}
|
||||
|
||||
public static X509Certificate2 GetSelfSignedCert(string subjectName)
|
||||
private static X509Certificate2 _GetCert(string name)
|
||||
{
|
||||
X509Certificate2 result = null;
|
||||
X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
|
||||
store.Open(OpenFlags.ReadOnly);
|
||||
|
||||
var name2 = new X500DistinguishedName(name);
|
||||
// ReSharper disable AssignNullToNotNullAttribute
|
||||
X509Certificate2Collection certs = store.Certificates.Find(X509FindType.FindBySubjectDistinguishedName, name2.Name, false);
|
||||
// ReSharper restore AssignNullToNotNullAttribute
|
||||
if (certs.Count > 0)
|
||||
result = certs[0];
|
||||
|
||||
store.Close();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private X509Certificate2 _GetSelfSignedCert(string subjectName)
|
||||
{
|
||||
var keyParam = new CngKeyCreationParameters
|
||||
{
|
||||
@@ -91,58 +141,103 @@ namespace WebserverInitalConfig
|
||||
byte[] rawData = key.CreateSelfSignedCertificate(param).Export(X509ContentType.Pfx, "");
|
||||
var cert = new X509Certificate2(rawData, "", X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet)
|
||||
{
|
||||
FriendlyName = "Vocaluxe Server Certificate"
|
||||
FriendlyName = _RuleName + " Server Certificate"
|
||||
};
|
||||
return cert;
|
||||
}
|
||||
|
||||
private static void _AddFirewallRuleForProfile(INetFwProfile profile, string exePath, int port, bool isTCP)
|
||||
public void CreateAndAddCert(string hostName)
|
||||
{
|
||||
bool isFirewallEnabled = profile.FirewallEnabled;
|
||||
string certName = "CN=" + hostName + ", C=DE, O=" + _RuleName + ", OU=" + _RuleName + " Server";
|
||||
|
||||
if (!isFirewallEnabled)
|
||||
return;
|
||||
INetFwAuthorizedApplications applications = profile.AuthorizedApplications;
|
||||
if (!(from INetFwAuthorizedApplication a in applications
|
||||
where a.ProcessImageFileName == exePath
|
||||
select a).Any())
|
||||
X509Certificate2 cert = _GetCert(certName);
|
||||
if (cert == null)
|
||||
{
|
||||
INetFwAuthorizedApplication application = (INetFwAuthorizedApplication)Activator.CreateInstance(
|
||||
Type.GetTypeFromCLSID(new Guid(CLSID_NetAuthApp)));
|
||||
|
||||
application.Name = "Vocaluxe";
|
||||
application.ProcessImageFileName = exePath;
|
||||
application.Enabled = true;
|
||||
application.Scope = NET_FW_SCOPE_.NET_FW_SCOPE_ALL;
|
||||
applications.Add(application);
|
||||
}
|
||||
INetFwOpenPorts openPorts = profile.GloballyOpenPorts;
|
||||
NET_FW_IP_PROTOCOL_ protocol = isTCP ? NET_FW_IP_PROTOCOL_.NET_FW_IP_PROTOCOL_TCP : NET_FW_IP_PROTOCOL_.NET_FW_IP_PROTOCOL_UDP;
|
||||
if (!(from INetFwOpenPort p in openPorts
|
||||
where (p.Port == port &&
|
||||
(p.Protocol == protocol))
|
||||
select p).Any())
|
||||
{
|
||||
INetFwOpenPort openPort = (INetFwOpenPort)Activator.CreateInstance(Type.GetTypeFromCLSID(new Guid(CLSID_NetOpenPort)));
|
||||
openPort.Enabled = true;
|
||||
openPort.Port = port;
|
||||
openPort.Protocol = protocol;
|
||||
openPort.Name = "Vocaluxe(" + port + ")";
|
||||
openPort.Scope = NET_FW_SCOPE_.NET_FW_SCOPE_ALL;
|
||||
|
||||
openPorts.Add(openPort);
|
||||
if (!IsAdministrator())
|
||||
throw new AuthenticationException();
|
||||
cert = _GetSelfSignedCert(certName);
|
||||
_AddCertToStore(cert);
|
||||
}
|
||||
_BindCert(cert);
|
||||
}
|
||||
|
||||
public static void AddFirewallRule(string exePath, int port, bool isTCP)
|
||||
private bool _IsAppAuthorized(INetFwProfile profile)
|
||||
{
|
||||
if (!profile.FirewallEnabled)
|
||||
return true;
|
||||
return profile.AuthorizedApplications.Cast<INetFwAuthorizedApplication>().Any(a => a.ProcessImageFileName == _ExePath);
|
||||
}
|
||||
|
||||
private bool _IsPortOpen(INetFwProfile profile)
|
||||
{
|
||||
NET_FW_IP_PROTOCOL_ protocol = _GetProtocol();
|
||||
|
||||
if (!profile.FirewallEnabled)
|
||||
return true;
|
||||
return profile.GloballyOpenPorts.Cast<INetFwOpenPort>().Any(p => p.Protocol == protocol && p.Port == _Port);
|
||||
}
|
||||
|
||||
private NET_FW_IP_PROTOCOL_ _GetProtocol()
|
||||
{
|
||||
return _IsTCP ? NET_FW_IP_PROTOCOL_.NET_FW_IP_PROTOCOL_TCP : NET_FW_IP_PROTOCOL_.NET_FW_IP_PROTOCOL_UDP;
|
||||
}
|
||||
|
||||
private void _AddFirewallRuleForProfile(INetFwProfile profile)
|
||||
{
|
||||
bool isAppAuthorized = _IsAppAuthorized(profile);
|
||||
bool isPortOpen = _IsPortOpen(profile);
|
||||
|
||||
if ((!isAppAuthorized || !isPortOpen) && !IsAdministrator())
|
||||
throw new AuthenticationException();
|
||||
if (!isAppAuthorized)
|
||||
_AddAppToFirewall(profile);
|
||||
|
||||
if (!isPortOpen)
|
||||
_AddPortToFirewall(profile);
|
||||
}
|
||||
|
||||
private void _AddPortToFirewall(INetFwProfile profile)
|
||||
{
|
||||
INetFwOpenPort openPort = (INetFwOpenPort)Activator.CreateInstance(Type.GetTypeFromCLSID(new Guid(CLSID_NetOpenPort)));
|
||||
openPort.Enabled = true;
|
||||
openPort.Port = _Port;
|
||||
openPort.Protocol = _GetProtocol();
|
||||
openPort.Name = _RuleName + "(" + _Port + ")";
|
||||
openPort.Scope = NET_FW_SCOPE_.NET_FW_SCOPE_ALL;
|
||||
|
||||
profile.GloballyOpenPorts.Add(openPort);
|
||||
}
|
||||
|
||||
private void _AddAppToFirewall(INetFwProfile profile)
|
||||
{
|
||||
INetFwAuthorizedApplication application = (INetFwAuthorizedApplication)Activator.CreateInstance(
|
||||
Type.GetTypeFromCLSID(new Guid(CLSID_NetAuthApp)));
|
||||
|
||||
application.Name = _RuleName;
|
||||
application.ProcessImageFileName = _ExePath;
|
||||
application.Enabled = true;
|
||||
application.Scope = NET_FW_SCOPE_.NET_FW_SCOPE_ALL;
|
||||
profile.AuthorizedApplications.Add(application);
|
||||
}
|
||||
|
||||
public static bool IsAdministrator()
|
||||
{
|
||||
WindowsIdentity identity = WindowsIdentity.GetCurrent();
|
||||
// ReSharper disable AssignNullToNotNullAttribute
|
||||
WindowsPrincipal principal = new WindowsPrincipal(identity);
|
||||
// ReSharper restore AssignNullToNotNullAttribute
|
||||
return principal.IsInRole(WindowsBuiltInRole.Administrator);
|
||||
}
|
||||
|
||||
public void AddFirewallRule()
|
||||
{
|
||||
INetFwMgr manage = (INetFwMgr)Activator.CreateInstance(Type.GetTypeFromCLSID(new Guid(CLSID_NetFwMgr)));
|
||||
//AddFirewallRuleForProfile(manage.LocalPolicy.CurrentProfile, exePath, port, isTCP);
|
||||
//_AddFirewallRuleForProfile(manage.LocalPolicy.CurrentProfile);
|
||||
//if (manage.CurrentProfileType != NET_FW_PROFILE_TYPE_.NET_FW_PROFILE_STANDARD)
|
||||
//Add to Home/Work(Private) and current net
|
||||
//TODO: This somewhow adds 2 entries each instead of only one that is activated for Home/Work and public nets
|
||||
_AddFirewallRuleForProfile(manage.LocalPolicy.GetProfileByType(NET_FW_PROFILE_TYPE_.NET_FW_PROFILE_STANDARD), exePath, port, isTCP);
|
||||
_AddFirewallRuleForProfile(manage.LocalPolicy.GetProfileByType(NET_FW_PROFILE_TYPE_.NET_FW_PROFILE_CURRENT), exePath, port, isTCP);
|
||||
_AddFirewallRuleForProfile(manage.LocalPolicy.GetProfileByType(NET_FW_PROFILE_TYPE_.NET_FW_PROFILE_STANDARD));
|
||||
_AddFirewallRuleForProfile(manage.LocalPolicy.GetProfileByType(NET_FW_PROFILE_TYPE_.NET_FW_PROFILE_CURRENT));
|
||||
}
|
||||
|
||||
/*public static X509Certificate2 getCert(string subject)
|
||||
|
||||
@@ -18,13 +18,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace WebserverInitalConfig
|
||||
{
|
||||
|
||||
@@ -16,34 +16,62 @@
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Security.Authentication;
|
||||
|
||||
namespace WebserverInitalConfig
|
||||
{
|
||||
class Program
|
||||
static class CProgram
|
||||
{
|
||||
// ReSharper disable InconsistentNaming
|
||||
private static void Main(string[] args)
|
||||
// ReSharper restore InconsistentNaming
|
||||
{
|
||||
if (args.Length != 2)
|
||||
int port;
|
||||
if (args.Length < 2 || !int.TryParse(args[0], out port))
|
||||
{
|
||||
Console.WriteLine("Usage: VocaluxeServerConfig port isHttps");
|
||||
Environment.Exit(-1);
|
||||
}
|
||||
|
||||
CConfigHttpApi.AddFirewallRule(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Vocaluxe.exe"), Int32.Parse(args[0]), true);
|
||||
|
||||
if (args[1].ToLower() == "true")
|
||||
{
|
||||
string hostname = Dns.GetHostName();
|
||||
X509Certificate2 cert = CConfigHttpApi.GetSelfSignedCert("CN=" + hostname + " C=DE O=Vocaluxe OU=Vocaluxe Server");
|
||||
CConfigHttpApi.AddCertToStore(cert);
|
||||
CConfigHttpApi.BindCert("0.0.0.0", Int32.Parse(args[0]), cert);
|
||||
CConfigHttpApi.ReserveUrl("https://+:" + args[0] + "/");
|
||||
}
|
||||
else
|
||||
CConfigHttpApi.ReserveUrl("http://+:" + args[0] + "/");
|
||||
{
|
||||
CConfigHttpApi config = new CConfigHttpApi("Vocaluxe", Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Vocaluxe.exe"), "0.0.0.0", port, true);
|
||||
try
|
||||
{
|
||||
config.AddFirewallRule();
|
||||
if (args[1].ToLower() == "true")
|
||||
config.CreateAndAddCert(Dns.GetHostName());
|
||||
|
||||
if ((args.Length >= 3 && args[2] == "reserve") || CConfigHttpApi.IsAdministrator())
|
||||
config.ReserveUrl();
|
||||
}
|
||||
catch (AuthenticationException)
|
||||
{
|
||||
ProcessStartInfo proc = new ProcessStartInfo
|
||||
{
|
||||
UseShellExecute = true,
|
||||
WorkingDirectory = Environment.CurrentDirectory,
|
||||
FileName = Process.GetCurrentProcess().MainModule.FileName,
|
||||
Arguments = args[0] + " " + args[1],
|
||||
Verb = "runas",
|
||||
CreateNoWindow = true,
|
||||
WindowStyle = ProcessWindowStyle.Hidden,
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
Process.Start(proc);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// The user refused the elevation.
|
||||
// Do nothing and return directly ...
|
||||
Environment.Exit(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,6 @@
|
||||
#endregion
|
||||
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// Allgemeine Informationen über eine Assembly werden über die folgenden
|
||||
|
||||
@@ -32,9 +32,6 @@
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<ApplicationIcon>Vocaluxe.ico</ApplicationIcon>
|
||||
</PropertyGroup>
|
||||
|
||||
Reference in new issue
Block a user