diff --git a/ClientServerLib/ClientServerLib/CDiscover.cs b/ClientServerLib/ClientServerLib/CDiscover.cs index 9dd5aa3d..17beab61 100644 --- a/ClientServerLib/ClientServerLib/CDiscover.cs +++ b/ClientServerLib/ClientServerLib/CDiscover.cs @@ -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 knownServer = new List(); 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); } } } \ No newline at end of file diff --git a/ClientServerLib/ClientServerLib/CServer.cs b/ClientServerLib/ClientServerLib/CServer.cs index ab704a95..51a6d2b7 100644 --- a/ClientServerLib/ClientServerLib/CServer.cs +++ b/ClientServerLib/ClientServerLib/CServer.cs @@ -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(); diff --git a/ClientServerLib/ClientServerLib/ICWebservice.cs b/ClientServerLib/ClientServerLib/ICWebservice.cs index 38f1d5d0..0305e418 100644 --- a/ClientServerLib/ClientServerLib/ICWebservice.cs +++ b/ClientServerLib/ClientServerLib/ICWebservice.cs @@ -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 } diff --git a/Output/Themes/Ambient/Screens/ScreenOptionsRecord.xml b/Output/Themes/Ambient/Screens/ScreenOptionsRecord.xml index b2620651..ba0ce824 100644 --- a/Output/Themes/Ambient/Screens/ScreenOptionsRecord.xml +++ b/Output/Themes/Ambient/Screens/ScreenOptionsRecord.xml @@ -1,7 +1,7 @@  - 3 + 4 Video @@ -216,6 +216,35 @@ + + 75 + 347 + + 0,00 + + 27 + + + + StaticColor + + + TextSColor + + Left + + Center + + + + Outline + + TR_SCREENORECORD_MIC_DELAY + + + + + 75 227 @@ -243,8 +272,8 @@ - - + + 75 287 @@ -272,36 +301,7 @@ - - - - 75 - 347 - - 0,00 - - 27 - - - - StaticColor - - - TextSColor - - Left - - Center - - - - Outline - - TR_SCREENORECORD_MIC_DELAY - - - - + 640 diff --git a/Output/Themes/Changelog/Changelog_ScreenOptionsRecord.txt b/Output/Themes/Changelog/Changelog_ScreenOptionsRecord.txt index 89d9465c..1eb9f362 100644 --- a/Output/Themes/Changelog/Changelog_ScreenOptionsRecord.txt +++ b/Output/Themes/Changelog/Changelog_ScreenOptionsRecord.txt @@ -6,4 +6,7 @@ Version 2: Add: and . This is a new theme-element. Check ScreenOptionsRecord.xml for style-possibilities. -++++++++++ \ No newline at end of file +++++++++++ +Version 4: +Rename Text 3/4 to TextChannel1/2 +Rename Text5 to Text3 \ No newline at end of file diff --git a/Vocaluxe/Base/CBackgroundMusic.cs b/Vocaluxe/Base/CBackgroundMusic.cs index 48c173a0..9afc32dd 100644 --- a/Vocaluxe/Base/CBackgroundMusic.cs +++ b/Vocaluxe/Base/CBackgroundMusic.cs @@ -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); } } diff --git a/Vocaluxe/Base/CConfig.cs b/Vocaluxe/Base/CConfig.cs index c5024d1e..2b5d8b3d 100644 --- a/Vocaluxe/Base/CConfig.cs +++ b/Vocaluxe/Base/CConfig.cs @@ -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; diff --git a/Vocaluxe/Base/CCursor.cs b/Vocaluxe/Base/CCursor.cs index 1ac568cd..94a1e495 100644 --- a/Vocaluxe/Base/CCursor.cs +++ b/Vocaluxe/Base/CCursor.cs @@ -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); } } } \ No newline at end of file diff --git a/Vocaluxe/Base/CDataBase.cs b/Vocaluxe/Base/CDataBase.cs index b755a95b..888ea52d 100644 --- a/Vocaluxe/Base/CDataBase.cs +++ b/Vocaluxe/Base/CDataBase.cs @@ -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 scores, SPlayer player) + public static List LoadScore(int songID, EGameMode gameMode) { + var scores = new List(); using (var connection = new SQLiteConnection()) { connection.ConnectionString = "Data Source=" + _HighscoreFilePath; - scores = new List(); - 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 /// 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; } /// @@ -972,8 +973,7 @@ namespace Vocaluxe.Base lastDateAdded = dateAdded; } } - if (reader != null) - reader.Dispose(); + reader.Dispose(); foreach (int id in ids) _IncreaseSongCounter(id, command); diff --git a/Vocaluxe/Base/CGame.cs b/Vocaluxe/Base/CGame.cs index 4953a767..009e585f 100644 --- a/Vocaluxe/Base/CGame.cs +++ b/Vocaluxe/Base/CGame.cs @@ -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; diff --git a/Vocaluxe/Base/CGraphics.cs b/Vocaluxe/Base/CGraphics.cs index 60356193..0966424a 100644 --- a/Vocaluxe/Base/CGraphics.cs +++ b/Vocaluxe/Base/CGraphics.cs @@ -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); diff --git a/Vocaluxe/Base/CLog.cs b/Vocaluxe/Base/CLog.cs index 6f87a74c..8afe6cd4 100644 --- a/Vocaluxe/Base/CLog.cs +++ b/Vocaluxe/Base/CLog.cs @@ -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) diff --git a/Vocaluxe/Base/CMain.cs b/Vocaluxe/Base/CMain.cs index fad6fe07..e0f02c3d 100644 --- a/Vocaluxe/Base/CMain.cs +++ b/Vocaluxe/Base/CMain.cs @@ -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 diff --git a/Vocaluxe/Base/CSettings.cs b/Vocaluxe/Base/CSettings.cs index e70a0d0c..e978691d 100644 --- a/Vocaluxe/Base/CSettings.cs +++ b/Vocaluxe/Base/CSettings.cs @@ -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; diff --git a/Vocaluxe/Base/CSongs.cs b/Vocaluxe/Base/CSongs.cs index 7aa205c9..14b2100e 100644 --- a/Vocaluxe/Base/CSongs.cs +++ b/Vocaluxe/Base/CSongs.cs @@ -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) diff --git a/Vocaluxe/Base/CSound.cs b/Vocaluxe/Base/CSound.cs index 7df51ad7..d6b55cbe 100644 --- a/Vocaluxe/Base/CSound.cs +++ b/Vocaluxe/Base/CSound.cs @@ -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(); - } - } } \ No newline at end of file diff --git a/Vocaluxe/Base/CTheme.cs b/Vocaluxe/Base/CTheme.cs index 52bbc631..35180bcb 100644 --- a/Vocaluxe/Base/CTheme.cs +++ b/Vocaluxe/Base/CTheme.cs @@ -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); diff --git a/Vocaluxe/Base/CVideo.cs b/Vocaluxe/Base/CVideo.cs index 5358b7e6..76a7ce5e 100644 --- a/Vocaluxe/Base/CVideo.cs +++ b/Vocaluxe/Base/CVideo.cs @@ -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() diff --git a/Vocaluxe/Base/Server/CCommands.cs b/Vocaluxe/Base/Server/CCommands.cs index be2b0bae..3d8b70d1 100644 --- a/Vocaluxe/Base/Server/CCommands.cs +++ b/Vocaluxe/Base/Server/CCommands.cs @@ -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(); } diff --git a/Vocaluxe/Base/Server/CVocaluxeServer.cs b/Vocaluxe/Base/Server/CVocaluxeServer.cs index 03ede100..154dd1db 100644 --- a/Vocaluxe/Base/Server/CVocaluxeServer.cs +++ b/Vocaluxe/Base/Server/CVocaluxeServer.cs @@ -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 photosOfThisRound = new List(); + private static readonly List _PhotosOfThisRound = new List(); 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) diff --git a/Vocaluxe/CProgrammHelper.cs b/Vocaluxe/CProgrammHelper.cs index 12cf6753..f4425776 100644 --- a/Vocaluxe/CProgrammHelper.cs +++ b/Vocaluxe/CProgrammHelper.cs @@ -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; diff --git a/Vocaluxe/Lib/Input/CHIDAPI.cs b/Vocaluxe/Lib/Input/CHIDAPI.cs index 3252373c..59d86148 100644 --- a/Vocaluxe/Lib/Input/CHIDAPI.cs +++ b/Vocaluxe/Lib/Input/CHIDAPI.cs @@ -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)] diff --git a/Vocaluxe/Lib/Input/WiiMote/CWiiMote.cs b/Vocaluxe/Lib/Input/WiiMote/CWiiMote.cs index d10c38e7..6aa70841 100644 --- a/Vocaluxe/Lib/Input/WiiMote/CWiiMote.cs +++ b/Vocaluxe/Lib/Input/WiiMote/CWiiMote.cs @@ -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(); _CurrentKeysPool = new List(); @@ -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); - } } } \ No newline at end of file diff --git a/Vocaluxe/Lib/Input/WiiMote/WiiMoteLib.cs b/Vocaluxe/Lib/Input/WiiMote/WiiMoteLib.cs index 7b1449d5..d25097d9 100644 --- a/Vocaluxe/Lib/Input/WiiMote/WiiMoteLib.cs +++ b/Vocaluxe/Lib/Input/WiiMote/WiiMoteLib.cs @@ -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 } } \ No newline at end of file diff --git a/Vocaluxe/Lib/Playlist/CPlaylistFile.cs b/Vocaluxe/Lib/Playlist/CPlaylistFile.cs index 954cc6a7..4ab37b0f 100644 --- a/Vocaluxe/Lib/Playlist/CPlaylistFile.cs +++ b/Vocaluxe/Lib/Playlist/CPlaylistFile.cs @@ -18,7 +18,6 @@ using System; using System.Collections.Generic; using System.IO; -using System.Text; using System.Xml; using Vocaluxe.Base; using VocaluxeLib; diff --git a/Vocaluxe/Lib/Sound/CBuffer.cs b/Vocaluxe/Lib/Sound/CBuffer.cs new file mode 100644 index 00000000..34831ccd --- /dev/null +++ b/Vocaluxe/Lib/Sound/CBuffer.cs @@ -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); + } + } +} \ No newline at end of file diff --git a/Vocaluxe/Lib/Sound/CDelayTest.cs b/Vocaluxe/Lib/Sound/CDelayTest.cs new file mode 100644 index 00000000..047b3999 --- /dev/null +++ b/Vocaluxe/Lib/Sound/CDelayTest.cs @@ -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(); + } + } + } +} \ No newline at end of file diff --git a/Vocaluxe/Lib/Sound/CDirectSoundRecord.cs b/Vocaluxe/Lib/Sound/CDirectSoundRecord.cs index 15fcc291..eabf0d73 100644 --- a/Vocaluxe/Lib/Sound/CDirectSoundRecord.cs +++ b/Vocaluxe/Lib/Sound/CDirectSoundRecord.cs @@ -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(); diff --git a/Vocaluxe/Lib/Sound/CGstreamerSharpAudio.cs b/Vocaluxe/Lib/Sound/CGstreamerSharpAudio.cs index b8270b32..dc856e98 100644 --- a/Vocaluxe/Lib/Sound/CGstreamerSharpAudio.cs +++ b/Vocaluxe/Lib/Sound/CGstreamerSharpAudio.cs @@ -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; } } } diff --git a/Vocaluxe/Lib/Sound/COpenALPlay.cs b/Vocaluxe/Lib/Sound/COpenALPlay.cs index caecc663..6ab9f2b4 100644 --- a/Vocaluxe/Lib/Sound/COpenALPlay.cs +++ b/Vocaluxe/Lib/Sound/COpenALPlay.cs @@ -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; } } } diff --git a/Vocaluxe/Lib/Sound/CPortAudioPlay.cs b/Vocaluxe/Lib/Sound/CPortAudioPlay.cs index 6cbf218b..2be82c2c 100644 --- a/Vocaluxe/Lib/Sound/CPortAudioPlay.cs +++ b/Vocaluxe/Lib/Sound/CPortAudioPlay.cs @@ -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; } } } diff --git a/Vocaluxe/Lib/Sound/CPortAudioRecord.cs b/Vocaluxe/Lib/Sound/CPortAudioRecord.cs index 982d63bb..37d6c808 100644 --- a/Vocaluxe/Lib/Sound/CPortAudioRecord.cs +++ b/Vocaluxe/Lib/Sound/CPortAudioRecord.cs @@ -246,7 +246,7 @@ namespace Vocaluxe.Lib.Sound if (!_Initialized) return 0; - return _Buffer[player].NumHalfTones; + return CBuffer.NumHalfTones; } public float[] ToneWeigth(int player) diff --git a/Vocaluxe/Lib/Sound/CPt1.cs b/Vocaluxe/Lib/Sound/CPt1.cs new file mode 100644 index 00000000..4ca4b951 --- /dev/null +++ b/Vocaluxe/Lib/Sound/CPt1.cs @@ -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(); + } + } +} \ No newline at end of file diff --git a/Vocaluxe/Lib/Sound/CSyncTimer.cs b/Vocaluxe/Lib/Sound/CSyncTimer.cs new file mode 100644 index 00000000..6ccd380c --- /dev/null +++ b/Vocaluxe/Lib/Sound/CSyncTimer.cs @@ -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(); + } + } +} \ No newline at end of file diff --git a/Vocaluxe/Lib/Sound/IPlayback.cs b/Vocaluxe/Lib/Sound/IPlayback.cs index 935956f5..22d7d7b7 100644 --- a/Vocaluxe/Lib/Sound/IPlayback.cs +++ b/Vocaluxe/Lib/Sound/IPlayback.cs @@ -17,6 +17,14 @@ namespace Vocaluxe.Lib.Sound { + public enum EStreamAction + { + Nothing, + Pause, + Stop, + Close + } + struct SAudioStreams { public int Handle; diff --git a/Vocaluxe/Lib/Video/Acinerella/CDecoder.cs b/Vocaluxe/Lib/Video/Acinerella/CDecoder.cs index 9591eaaa..743d5747 100644 --- a/Vocaluxe/Lib/Video/Acinerella/CDecoder.cs +++ b/Vocaluxe/Lib/Video/Acinerella/CDecoder.cs @@ -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 } } \ No newline at end of file diff --git a/Vocaluxe/Lib/Video/Acinerella/CDecoderThread.cs b/Vocaluxe/Lib/Video/Acinerella/CDecoderThread.cs new file mode 100644 index 00000000..2b254b98 --- /dev/null +++ b/Vocaluxe/Lib/Video/Acinerella/CDecoderThread.cs @@ -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; + } + + /// + /// Gets a frame + /// + /// Referenz to texture where frame should be put in (can be null, then texture is created) + /// Maximum start time for frame + /// Set to whether there are no more frames (stream finished, no loop, future calls will always return false) + /// True if a new frame was gotten + 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(); + } + } +} \ No newline at end of file diff --git a/Vocaluxe/Lib/Video/Acinerella/CFramebuffer.cs b/Vocaluxe/Lib/Video/Acinerella/CFramebuffer.cs index b0c2704f..4ea6c543 100644 --- a/Vocaluxe/Lib/Video/Acinerella/CFramebuffer.cs +++ b/Vocaluxe/Lib/Video/Acinerella/CFramebuffer.cs @@ -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; } } } \ No newline at end of file diff --git a/Vocaluxe/Program.cs b/Vocaluxe/Program.cs index 5d254c13..b59d4f9e 100644 --- a/Vocaluxe/Program.cs +++ b/Vocaluxe/Program.cs @@ -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) { diff --git a/Vocaluxe/Properties/AssemblyInfo.cs b/Vocaluxe/Properties/AssemblyInfo.cs index 840ed612..861326f6 100644 --- a/Vocaluxe/Properties/AssemblyInfo.cs +++ b/Vocaluxe/Properties/AssemblyInfo.cs @@ -49,5 +49,5 @@ using System.Runtime.InteropServices; // Revision // -[assembly: AssemblyVersion("0.3.0.82")] -[assembly: AssemblyFileVersion("0.3.0.82")] \ No newline at end of file +[assembly: AssemblyVersion("0.3.0.83")] +[assembly: AssemblyFileVersion("0.3.0.83")] \ No newline at end of file diff --git a/Vocaluxe/Screens/CPopupScreenServerQR.cs b/Vocaluxe/Screens/CPopupScreenServerQR.cs index 94ad9f74..a961edd9 100644 --- a/Vocaluxe/Screens/CPopupScreenServerQR.cs +++ b/Vocaluxe/Screens/CPopupScreenServerQR.cs @@ -15,7 +15,6 @@ // along with Vocaluxe. If not, see . #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(); diff --git a/Vocaluxe/Screens/CScreenCredits.cs b/Vocaluxe/Screens/CScreenCredits.cs index 06d36d1f..7c340a7a 100644 --- a/Vocaluxe/Screens/CScreenCredits.cs +++ b/Vocaluxe/Screens/CScreenCredits.cs @@ -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; diff --git a/Vocaluxe/Screens/CScreenHighscore.cs b/Vocaluxe/Screens/CScreenHighscore.cs index 933c2706..01848911 100644 --- a/Vocaluxe/Screens/CScreenHighscore.cs +++ b/Vocaluxe/Screens/CScreenHighscore.cs @@ -44,7 +44,7 @@ namespace Vocaluxe.Screens private string[] _TextDate; private string[] _ParticleEffectNew; - private List[] _Scores; + private List[] _Scores; private List _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[points.NumRounds]; - for (int i = 0; i < _Scores.Length; i++) - _Scores[i] = new List(); _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[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(); } diff --git a/Vocaluxe/Screens/CScreenLoad.cs b/Vocaluxe/Screens/CScreenLoad.cs index e5ccaae2..4b6cf767 100644 --- a/Vocaluxe/Screens/CScreenLoad.cs +++ b/Vocaluxe/Screens/CScreenLoad.cs @@ -15,7 +15,6 @@ // along with Vocaluxe. If not, see . #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; } } diff --git a/Vocaluxe/Screens/CScreenNames.cs b/Vocaluxe/Screens/CScreenNames.cs index ba83f871..be65f5cc 100644 --- a/Vocaluxe/Screens/CScreenNames.cs +++ b/Vocaluxe/Screens/CScreenNames.cs @@ -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 diff --git a/Vocaluxe/Screens/CScreenOptionsRecord.cs b/Vocaluxe/Screens/CScreenOptionsRecord.cs index 3d8bdbf8..979809c6 100644 --- a/Vocaluxe/Screens/CScreenOptionsRecord.cs +++ b/Vocaluxe/Screens/CScreenOptionsRecord.cs @@ -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 _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) diff --git a/Vocaluxe/Screens/CScreenOptionsVideoAdjustments.cs b/Vocaluxe/Screens/CScreenOptionsVideoAdjustments.cs index 774ef686..6c22392b 100644 --- a/Vocaluxe/Screens/CScreenOptionsVideoAdjustments.cs +++ b/Vocaluxe/Screens/CScreenOptionsVideoAdjustments.cs @@ -15,12 +15,10 @@ // along with Vocaluxe. If not, see . #endregion -using System; using System.Windows.Forms; using Vocaluxe.Base; using VocaluxeLib; using VocaluxeLib.Menu; -using VocaluxeLib.Draw; namespace Vocaluxe.Screens { diff --git a/Vocaluxe/Screens/CScreenScore.cs b/Vocaluxe/Screens/CScreenScore.cs index af7525f5..db70f56e 100644 --- a/Vocaluxe/Screens/CScreenScore.cs +++ b/Vocaluxe/Screens/CScreenScore.cs @@ -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); diff --git a/Vocaluxe/SongQueue/CSongQueue.cs b/Vocaluxe/SongQueue/CSongQueue.cs index e2a461cf..cbfa7acf 100644 --- a/Vocaluxe/SongQueue/CSongQueue.cs +++ b/Vocaluxe/SongQueue/CSongQueue.cs @@ -39,7 +39,7 @@ namespace Vocaluxe.SongQueue class CSongQueue : ISongQueue { private List _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; } + /// + /// Get current round nr (1 ~ n) + /// + /// current round nr (1 ~ n) public int GetCurrentRoundNr() { - return _CurrentSong + 1; + return _CurrentRound + 1; } + /// + /// Returns current round + /// + /// Current round (0 based) + public int GetCurrentRound() + { + return _CurrentRound; + } + + /// + /// Get current song + /// + /// Song of current round or null if there is none/game finished 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) + /// + /// Get song of specified round + /// + /// Round (0 based) + /// Current song or null if out of bounds + 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) + /// + /// Get gameMode of specified round + /// + /// Round (0 based) + /// Current song or null if out of bounds + 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; } diff --git a/Vocaluxe/SongQueue/ISongQueue.cs b/Vocaluxe/SongQueue/ISongQueue.cs index c3e32f45..1831fd74 100644 --- a/Vocaluxe/SongQueue/ISongQueue.cs +++ b/Vocaluxe/SongQueue/ISongQueue.cs @@ -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); } } \ No newline at end of file diff --git a/Vocaluxe/Vocaluxe.csproj b/Vocaluxe/Vocaluxe.csproj index 51c3fb35..1b5d5b87 100644 --- a/Vocaluxe/Vocaluxe.csproj +++ b/Vocaluxe/Vocaluxe.csproj @@ -212,11 +212,14 @@ + + + @@ -251,7 +254,9 @@ + + @@ -484,4 +489,4 @@ --> - + \ No newline at end of file diff --git a/Vocaluxe/Website/css/style.css b/Vocaluxe/Website/css/style.css index 95fde798..585e930c 100644 --- a/Vocaluxe/Website/css/style.css +++ b/Vocaluxe/Website/css/style.css @@ -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; diff --git a/VocaluxeLib/CFading.cs b/VocaluxeLib/CFading.cs new file mode 100644 index 00000000..0b6761cb --- /dev/null +++ b/VocaluxeLib/CFading.cs @@ -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 . +#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(); + + /// + /// Starts a fading process adjusting between 2 values over a given amount of time + /// + /// Start value + /// Target value + /// Duration of the fading in seconds + public CFading(float fromValue, float toValue, float duration) + { + if (duration < 0) + duration = 0; + _FromValue = fromValue; + _ToValue = toValue; + _Duration = duration * 1000f; + _Timer.Start(); + } + + /// + /// Gets the current value and sets finished + /// + /// Set to whether fading has finished + /// Current value (between from and to values) + 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; + } + } +} \ No newline at end of file diff --git a/VocaluxeLib/CHelper.cs b/VocaluxeLib/CHelper.cs index 6d0bc3ae..a03b1ad9 100644 --- a/VocaluxeLib/CHelper.cs +++ b/VocaluxeLib/CHelper.cs @@ -47,6 +47,15 @@ namespace VocaluxeLib return (int)result; } + public static T Clamp(this T val, T min, T max) where T : IComparable + { + if (val.CompareTo(min) < 0) + return min; + if (val.CompareTo(max) > 0) + return max; + return val; + } + /// /// Concat strings into one string with ", " as separator. /// diff --git a/VocaluxeLib/Enums.cs b/VocaluxeLib/Enums.cs index 8e68a52c..5ac45bd3 100644 --- a/VocaluxeLib/Enums.cs +++ b/VocaluxeLib/Enums.cs @@ -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 } } \ No newline at end of file diff --git a/VocaluxeLib/Extensions.cs b/VocaluxeLib/Extensions.cs index 8def331c..4cc4fe2e 100644 --- a/VocaluxeLib/Extensions.cs +++ b/VocaluxeLib/Extensions.cs @@ -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 { /// /// Resizes the given list to the given size. Removes elements or adds default values diff --git a/VocaluxeLib/Game/CPoints.cs b/VocaluxeLib/Game/CPoints.cs index 00749b0f..7326ccf6 100644 --- a/VocaluxeLib/Game/CPoints.cs +++ b/VocaluxeLib/Game/CPoints.cs @@ -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; diff --git a/VocaluxeLib/IBasic.cs b/VocaluxeLib/IBasic.cs index 682597b4..334221a0 100644 --- a/VocaluxeLib/IBasic.cs +++ b/VocaluxeLib/IBasic.cs @@ -155,6 +155,8 @@ namespace VocaluxeLib public interface ILog { void LogError(string errorText); + void LogDebug(string text); + void LogSongInfo(string text); } public interface IFonts diff --git a/VocaluxeLib/Menu/CBackground.cs b/VocaluxeLib/Menu/CBackground.cs index b63de885..7138d3f3 100644 --- a/VocaluxeLib/Menu/CBackground.cs +++ b/VocaluxeLib/Menu/CBackground.cs @@ -54,8 +54,8 @@ namespace VocaluxeLib.Menu private bool _ThemeLoaded; private int _SlideShowCurrent; - private Stopwatch _SlideShowTimer = new Stopwatch(); - private List _SlideShowTextures = new List(); + private readonly Stopwatch _SlideShowTimer = new Stopwatch(); + private readonly List _SlideShowTextures = new List(); public SColorF Color; @@ -69,8 +69,7 @@ namespace VocaluxeLib.Menu { _PartyModeID = partyModeID; _ThemeLoaded = false; - _Theme = new SThemeBackground(); - _Theme.SlideShowTextures = new List(); + _Theme = new SThemeBackground {SlideShowTextures = new List()}; 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); diff --git a/VocaluxeLib/Menu/CLyric.cs b/VocaluxeLib/Menu/CLyric.cs index f4315702..a1c72daa 100644 --- a/VocaluxeLib/Menu/CLyric.cs +++ b/VocaluxeLib/Menu/CLyric.cs @@ -16,8 +16,6 @@ #endregion using System; -using System.Collections.Generic; -using System.Drawing; using System.Xml; using VocaluxeLib.Songs; diff --git a/VocaluxeLib/Menu/CMenu.cs b/VocaluxeLib/Menu/CMenu.cs index 73e53958..c64c9400 100644 --- a/VocaluxeLib/Menu/CMenu.cs +++ b/VocaluxeLib/Menu/CMenu.cs @@ -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; diff --git a/VocaluxeLib/Menu/CMenuPartyNameSelection.cs b/VocaluxeLib/Menu/CMenuPartyNameSelection.cs index 1b8686a4..76015829 100644 --- a/VocaluxeLib/Menu/CMenuPartyNameSelection.cs +++ b/VocaluxeLib/Menu/CMenuPartyNameSelection.cs @@ -15,11 +15,8 @@ // along with Vocaluxe. If not, see . #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[_NumTeams]; - else - _TeamList = new List[1]; + _TeamList = new List[_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 ids = new List(); ids.AddRange(_TeamList[t]); - for (int p = 0; p < ids.Count; p++) - _RemovePlayer(t, ids[p]); + foreach (int id in ids) + _RemovePlayer(t, id); } } diff --git a/VocaluxeLib/Menu/CNameSelection.cs b/VocaluxeLib/Menu/CNameSelection.cs index 301c2d04..3fd10b95 100644 --- a/VocaluxeLib/Menu/CNameSelection.cs +++ b/VocaluxeLib/Menu/CNameSelection.cs @@ -94,7 +94,7 @@ namespace VocaluxeLib.Menu private int _Player = -1; private readonly List _VisibleProfiles; - private List _UsedProfiles; + private readonly List _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 diff --git a/VocaluxeLib/Menu/SongMenu/CSongMenu.cs b/VocaluxeLib/Menu/SongMenu/CSongMenu.cs index 7d5e75fa..964a2ab5 100644 --- a/VocaluxeLib/Menu/SongMenu/CSongMenu.cs +++ b/VocaluxeLib/Menu/SongMenu/CSongMenu.cs @@ -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(); } } } \ No newline at end of file diff --git a/VocaluxeLib/Menu/SongMenu/CSongMenuFramework.cs b/VocaluxeLib/Menu/SongMenu/CSongMenuFramework.cs index 211da48f..9cdd19dd 100644 --- a/VocaluxeLib/Menu/SongMenu/CSongMenuFramework.cs +++ b/VocaluxeLib/Menu/SongMenu/CSongMenuFramework.cs @@ -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 _Streams = new List(); 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); } } } diff --git a/VocaluxeLib/Menu/SongMenu/CSongMenuTileBoard.cs b/VocaluxeLib/Menu/SongMenu/CSongMenuTileBoard.cs index 2beb4e95..46781018 100644 --- a/VocaluxeLib/Menu/SongMenu/CSongMenuTileBoard.cs +++ b/VocaluxeLib/Menu/SongMenu/CSongMenuTileBoard.cs @@ -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()) diff --git a/VocaluxeLib/Profile/CAvatar.cs b/VocaluxeLib/Profile/CAvatar.cs index 716884c6..1928c915 100644 --- a/VocaluxeLib/Profile/CAvatar.cs +++ b/VocaluxeLib/Profile/CAvatar.cs @@ -49,7 +49,7 @@ namespace VocaluxeLib.Profile CBase.Drawing.RemoveTexture(ref Texture); } - public string getFileName() + public string GetFileName() { return FileName; } diff --git a/VocaluxeLib/Profile/CProfile.cs b/VocaluxeLib/Profile/CProfile.cs index 7d4e2b54..4e27b4bd 100644 --- a/VocaluxeLib/Profile/CProfile.cs +++ b/VocaluxeLib/Profile/CProfile.cs @@ -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) diff --git a/VocaluxeLib/Songs/CLineBase.cs b/VocaluxeLib/Songs/CLineBase.cs index 16023f42..6c972851 100644 --- a/VocaluxeLib/Songs/CLineBase.cs +++ b/VocaluxeLib/Songs/CLineBase.cs @@ -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() diff --git a/VocaluxeLib/Songs/CSong.cs b/VocaluxeLib/Songs/CSong.cs index e711cd94..c16c1874 100644 --- a/VocaluxeLib/Songs/CSong.cs +++ b/VocaluxeLib/Songs/CSong.cs @@ -97,7 +97,7 @@ namespace VocaluxeLib.Songs public string MP3FileName = String.Empty; public string CoverFileName = String.Empty; - public List BackgroundFileNames = new List(); + public readonly List BackgroundFileNames = new List(); public string VideoFileName = String.Empty; public EAspect VideoAspect = EAspect.Crop; diff --git a/VocaluxeLib/Songs/CSongLoader.cs b/VocaluxeLib/Songs/CSongLoader.cs index 98ba075c..8c959583 100644 --- a/VocaluxeLib/Songs/CSongLoader.cs +++ b/VocaluxeLib/Songs/CSongLoader.cs @@ -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) diff --git a/VocaluxeLib/Songs/CSungNote.cs b/VocaluxeLib/Songs/CSungNote.cs index 7dd0e8f7..3fd3b9a1 100644 --- a/VocaluxeLib/Songs/CSungNote.cs +++ b/VocaluxeLib/Songs/CSungNote.cs @@ -41,6 +41,7 @@ namespace VocaluxeLib.Songs /// /// /// + /// public CSungNote(int startBeat, int duration, int tone, CSongNote hitNote, double points) : this(startBeat, duration, tone) { HitNote = hitNote; diff --git a/VocaluxeLib/Songs/CVoice.cs b/VocaluxeLib/Songs/CVoice.cs index 27aaeae0..c9784a3a 100644 --- a/VocaluxeLib/Songs/CVoice.cs +++ b/VocaluxeLib/Songs/CVoice.cs @@ -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)) diff --git a/VocaluxeLib/Structs.cs b/VocaluxeLib/Structs.cs index 4bef014d..13ee20ca 100644 --- a/VocaluxeLib/Structs.cs +++ b/VocaluxeLib/Structs.cs @@ -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; } diff --git a/VocaluxeLib/VocaluxeLib.csproj b/VocaluxeLib/VocaluxeLib.csproj index d44d9b74..22d6a2b1 100644 --- a/VocaluxeLib/VocaluxeLib.csproj +++ b/VocaluxeLib/VocaluxeLib.csproj @@ -130,6 +130,7 @@ + diff --git a/WebserverInitalConfig/CConfigHttpApi.cs b/WebserverInitalConfig/CConfigHttpApi.cs index 4bbd3ed9..38002df3 100644 --- a/WebserverInitalConfig/CConfigHttpApi.cs +++ b/WebserverInitalConfig/CConfigHttpApi.cs @@ -15,6 +15,8 @@ // along with Vocaluxe. If not, see . #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().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().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) diff --git a/WebserverInitalConfig/HttpApi.cs b/WebserverInitalConfig/HttpApi.cs index c248f8b6..39f587ff 100644 --- a/WebserverInitalConfig/HttpApi.cs +++ b/WebserverInitalConfig/HttpApi.cs @@ -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 { diff --git a/WebserverInitalConfig/Program.cs b/WebserverInitalConfig/Program.cs index 4b7ce630..fc09dac1 100644 --- a/WebserverInitalConfig/Program.cs +++ b/WebserverInitalConfig/Program.cs @@ -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); + } + } + } } } } \ No newline at end of file diff --git a/WebserverInitalConfig/Properties/AssemblyInfo.cs b/WebserverInitalConfig/Properties/AssemblyInfo.cs index 4665bfa0..4a79c1a6 100644 --- a/WebserverInitalConfig/Properties/AssemblyInfo.cs +++ b/WebserverInitalConfig/Properties/AssemblyInfo.cs @@ -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 diff --git a/WebserverInitalConfig/WebserverInitalConfig.csproj b/WebserverInitalConfig/WebserverInitalConfig.csproj index 7544f7a3..2f48f927 100644 --- a/WebserverInitalConfig/WebserverInitalConfig.csproj +++ b/WebserverInitalConfig/WebserverInitalConfig.csproj @@ -32,9 +32,6 @@ prompt 4 - - app.manifest - Vocaluxe.ico