From 9bfedf3cf0e7d0e8f37f525a106dcf475cd7276a Mon Sep 17 00:00:00 2001 From: Flamefire Date: Wed, 25 Sep 2013 20:19:22 +0200 Subject: [PATCH 01/38] Rename SScores --- Vocaluxe/Base/CDataBase.cs | 8 ++++---- Vocaluxe/Screens/CScreenHighscore.cs | 8 ++++---- VocaluxeLib/Structs.cs | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Vocaluxe/Base/CDataBase.cs b/Vocaluxe/Base/CDataBase.cs index b755a95b..cf37bf3b 100644 --- a/Vocaluxe/Base/CDataBase.cs +++ b/Vocaluxe/Base/CDataBase.cs @@ -243,13 +243,13 @@ namespace Vocaluxe.Base return lastInsertID; } - public static void LoadScore(out List scores, SPlayer player) + public static void LoadScore(out List scores, SPlayer player) { using (var connection = new SQLiteConnection()) { connection.ConnectionString = "Data Source=" + _HighscoreFilePath; - scores = new List(); + scores = new List(); try { @@ -290,13 +290,13 @@ namespace Vocaluxe.Base { while (reader.Read()) { - var score = new SScores + 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), - LineNr = reader.GetInt32(4), + VoiceNr = reader.GetInt32(4), ID = reader.GetInt32(5) }; diff --git a/Vocaluxe/Screens/CScreenHighscore.cs b/Vocaluxe/Screens/CScreenHighscore.cs index 933c2706..a8be7e46 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"); @@ -195,9 +195,9 @@ namespace Vocaluxe.Screens _Round = 0; _Pos = 0; CPoints points = CGame.GetPoints(); - _Scores = new List[points.NumRounds]; + _Scores = new List[points.NumRounds]; for (int i = 0; i < _Scores.Length; i++) - _Scores[i] = new List(); + _Scores[i] = new List(); _NewEntryIDs.Clear(); _AddScoresToDB(); _LoadScores(); diff --git a/VocaluxeLib/Structs.cs b/VocaluxeLib/Structs.cs index 4bef014d..895d593b 100644 --- a/VocaluxeLib/Structs.cs +++ b/VocaluxeLib/Structs.cs @@ -197,13 +197,13 @@ namespace VocaluxeLib 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; } From e3f744677e25a29cf7e6a89d6bf1eb989f23e398 Mon Sep 17 00:00:00 2001 From: Flamefire Date: Thu, 26 Sep 2013 13:47:19 +0200 Subject: [PATCH 02/38] Better handling of Points (Preparation for future changes) Fix some warnings of unused results (show errors on failure!) --- Vocaluxe/Base/CDataBase.cs | 206 +++++++++++++-------------- Vocaluxe/Base/CGame.cs | 6 +- Vocaluxe/Screens/CScreenCredits.cs | 30 ++-- Vocaluxe/Screens/CScreenHighscore.cs | 2 +- Vocaluxe/SongQueue/CSongQueue.cs | 4 +- VocaluxeLib/Game/CPoints.cs | 14 +- VocaluxeLib/Structs.cs | 4 +- 7 files changed, 129 insertions(+), 137 deletions(-) diff --git a/Vocaluxe/Base/CDataBase.cs b/Vocaluxe/Base/CDataBase.cs index cf37bf3b..ada2a0a6 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,7 +247,7 @@ namespace Vocaluxe.Base return lastInsertID; } - public static void LoadScore(out List scores, SPlayer player) + public static void LoadScore(out List scores, int songID, EGameMode gameMode) { using (var connection = new SQLiteConnection()) { @@ -263,47 +267,51 @@ namespace Vocaluxe.Base 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; + + 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 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) - }; + 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(); } } } @@ -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 dced2fa5..c64eaabc 100644 --- a/Vocaluxe/Base/CGame.cs +++ b/Vocaluxe/Base/CGame.cs @@ -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; } @@ -384,7 +382,7 @@ namespace Vocaluxe.Base { if (note.StartBeat < nextStart) { - if (note.Hit && note.HitNote.NoteType==ENoteType.Golden) + if (note.Hit && note.HitNote.NoteType == ENoteType.Golden) Players[p].PointsGoldenNotes += note.Points; Players[p].Points += note.Points; } 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 a8be7e46..9a75c943 100644 --- a/Vocaluxe/Screens/CScreenHighscore.cs +++ b/Vocaluxe/Screens/CScreenHighscore.cs @@ -239,7 +239,7 @@ namespace Vocaluxe.Screens for (int round = 0; round < points.NumRounds; round++) { SPlayer player = points.GetPlayer(round, CGame.NumPlayer)[0]; - CDataBase.LoadScore(out _Scores[round], player); + CDataBase.LoadScore(out _Scores[round], player.SongID, player.GameMode); } } diff --git a/Vocaluxe/SongQueue/CSongQueue.cs b/Vocaluxe/SongQueue/CSongQueue.cs index b23f1288..d11aeb4c 100644 --- a/Vocaluxe/SongQueue/CSongQueue.cs +++ b/Vocaluxe/SongQueue/CSongQueue.cs @@ -123,9 +123,7 @@ namespace Vocaluxe.SongQueue _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); + _SongQueue[_CurrentSong].GameMode); } _CurrentSong++; } 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/Structs.cs b/VocaluxeLib/Structs.cs index 895d593b..13ee20ca 100644 --- a/VocaluxeLib/Structs.cs +++ b/VocaluxeLib/Structs.cs @@ -190,9 +190,7 @@ 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; } From c27ae20b771019be802c2554896c3b43f23c93d7 Mon Sep 17 00:00:00 2001 From: Flamefire Date: Fri, 27 Sep 2013 17:14:28 +0200 Subject: [PATCH 03/38] Change min/max in LineBase to use simpler LINQ query --- VocaluxeLib/Songs/CLineBase.cs | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/VocaluxeLib/Songs/CLineBase.cs b/VocaluxeLib/Songs/CLineBase.cs index 0a819509..41d88909 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.Max(note => note.Tone); + int max = _Notes.Min(note => note.Tone); return min - (max - min) / 4; } From 074a1ba82dbfd61f8aa56491c67f441214ad5f20 Mon Sep 17 00:00:00 2001 From: Flamefire Date: Fri, 4 Oct 2013 23:02:54 +0200 Subject: [PATCH 04/38] Change signature of getDBScores --- Vocaluxe/Base/CDataBase.cs | 10 +++++----- Vocaluxe/Base/CGame.cs | 8 ++++---- Vocaluxe/Screens/CScreenHighscore.cs | 17 ++++++----------- 3 files changed, 15 insertions(+), 20 deletions(-) diff --git a/Vocaluxe/Base/CDataBase.cs b/Vocaluxe/Base/CDataBase.cs index ada2a0a6..888ea52d 100644 --- a/Vocaluxe/Base/CDataBase.cs +++ b/Vocaluxe/Base/CDataBase.cs @@ -247,21 +247,20 @@ namespace Vocaluxe.Base return lastInsertID; } - public static void LoadScore(out List scores, int songID, EGameMode gameMode) + 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)) @@ -284,7 +283,7 @@ namespace Vocaluxe.Base int dataBaseSongID = _GetDataBaseSongID(songID, command); if (dataBaseSongID < 0) - return; + 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 " + @@ -315,6 +314,7 @@ namespace Vocaluxe.Base } } } + return scores; } private static void _IncreaseSongCounter(int dataBaseSongID, SQLiteCommand command) diff --git a/Vocaluxe/Base/CGame.cs b/Vocaluxe/Base/CGame.cs index c64eaabc..de97c5b0 100644 --- a/Vocaluxe/Base/CGame.cs +++ b/Vocaluxe/Base/CGame.cs @@ -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() diff --git a/Vocaluxe/Screens/CScreenHighscore.cs b/Vocaluxe/Screens/CScreenHighscore.cs index 9a75c943..ab44c452 100644 --- a/Vocaluxe/Screens/CScreenHighscore.cs +++ b/Vocaluxe/Screens/CScreenHighscore.cs @@ -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.SongID, player.GameMode); + int songID = CGame.GetSong(round).ID; + EGameMode gameMode = CGame.GetGameMode(round); + _Scores[round] = CDataBase.LoadScore(songID, gameMode); } } From e6d8cf3ad942fb81075fb739be5ee8ab8d7cbd0d Mon Sep 17 00:00:00 2001 From: Flamefire Date: Tue, 8 Oct 2013 17:26:38 +0200 Subject: [PATCH 05/38] Fix crash --- Vocaluxe/Base/CGame.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/Vocaluxe/Base/CGame.cs b/Vocaluxe/Base/CGame.cs index de97c5b0..d8ea972c 100644 --- a/Vocaluxe/Base/CGame.cs +++ b/Vocaluxe/Base/CGame.cs @@ -404,9 +404,6 @@ 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); From 271772301df8a148c0c41107f204a320a3e28d74 Mon Sep 17 00:00:00 2001 From: Flamefire Date: Tue, 8 Oct 2013 18:01:08 +0200 Subject: [PATCH 06/38] Fix some bugs where round was actually roundNr Now round (0 based) is always used --- Vocaluxe/Base/CGame.cs | 2 +- Vocaluxe/Screens/CScreenHighscore.cs | 25 +++------ Vocaluxe/Screens/CScreenNames.cs | 12 ++--- Vocaluxe/Screens/CScreenScore.cs | 31 ++++++------ Vocaluxe/SongQueue/CSongQueue.cs | 76 ++++++++++++++++++---------- Vocaluxe/SongQueue/ISongQueue.cs | 12 ++--- VocaluxeLib/CHelper.cs | 9 ++++ 7 files changed, 92 insertions(+), 75 deletions(-) diff --git a/Vocaluxe/Base/CGame.cs b/Vocaluxe/Base/CGame.cs index d8ea972c..ada61872 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() diff --git a/Vocaluxe/Screens/CScreenHighscore.cs b/Vocaluxe/Screens/CScreenHighscore.cs index ab44c452..411cd2cd 100644 --- a/Vocaluxe/Screens/CScreenHighscore.cs +++ b/Vocaluxe/Screens/CScreenHighscore.cs @@ -242,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; @@ -250,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"; @@ -279,28 +279,15 @@ namespace Vocaluxe.Screens private void _ChangePos(int num) { - if (num > 0) - { - if (_Pos + num + _NumEntrys < _Scores[_Round].Count) - _Pos += num; - } - if (num < 0) - { - _Pos += num; - if (_Pos < 0) - _Pos = 0; - } + _Pos += num; + _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/CScreenNames.cs b/Vocaluxe/Screens/CScreenNames.cs index f1f548ab..6ad757c9 100644 --- a/Vocaluxe/Screens/CScreenNames.cs +++ b/Vocaluxe/Screens/CScreenNames.cs @@ -239,7 +239,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; @@ -603,12 +603,12 @@ namespace Vocaluxe.Screens CProfiles.GetAvatarTextureFromProfile(CGame.Players[i].ProfileID) : _OriginalPlayerAvatarTextures[i]; _Texts[_TextPlayer[i]].Text = CProfiles.GetPlayerName(CGame.Players[i].ProfileID, i + 1); - if (CGame.GetNumSongs() == 1 && CGame.GetSong(1).IsDuet) + if (CGame.GetNumSongs() == 1 && CGame.GetSong(0).IsDuet) { _SelectSlides[_SelectSlideDuetPlayer[i]].Clear(); _SelectSlides[_SelectSlideDuetPlayer[i]].Visible = i + 1 <= CGame.NumPlayer; - _SelectSlides[_SelectSlideDuetPlayer[i]].AddValue(CGame.GetSong(1).DuetPart1); - _SelectSlides[_SelectSlideDuetPlayer[i]].AddValue(CGame.GetSong(1).DuetPart2); + _SelectSlides[_SelectSlideDuetPlayer[i]].AddValue(CGame.GetSong(0).DuetPart1); + _SelectSlides[_SelectSlideDuetPlayer[i]].AddValue(CGame.GetSong(0).DuetPart2); _SelectSlides[_SelectSlideDuetPlayer[i]].Selection = i % 2; } else @@ -623,7 +623,7 @@ namespace Vocaluxe.Screens { for (int i = 0; i < CGame.NumPlayer; i++) { - if (CGame.GetNumSongs() == 1 && CGame.GetSong(1).IsDuet) + if (CGame.GetNumSongs() == 1 && CGame.GetSong(0).IsDuet) CGame.Players[i].VoiceNr = _SelectSlides[_SelectSlideDuetPlayer[i]].Selection; } @@ -652,7 +652,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/CScreenScore.cs b/Vocaluxe/Screens/CScreenScore.cs index fac4c499..51cd0273 100644 --- a/Vocaluxe/Screens/CScreenScore.cs +++ b/Vocaluxe/Screens/CScreenScore.cs @@ -118,7 +118,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(); @@ -130,8 +131,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++) @@ -263,7 +264,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) @@ -271,8 +272,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 { @@ -386,16 +387,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() diff --git a/Vocaluxe/SongQueue/CSongQueue.cs b/Vocaluxe/SongQueue/CSongQueue.cs index d11aeb4c..3fb3169f 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,37 +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); - } - _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() @@ -151,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/VocaluxeLib/CHelper.cs b/VocaluxeLib/CHelper.cs index ad04b6db..04ea1a90 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. /// From f97547693340521b812ff6bc9bd153a28224b16c Mon Sep 17 00:00:00 2001 From: Flamefire Date: Mon, 21 Oct 2013 16:15:27 +0200 Subject: [PATCH 07/38] Fix typo --- VocaluxeLib/Songs/CLineBase.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/VocaluxeLib/Songs/CLineBase.cs b/VocaluxeLib/Songs/CLineBase.cs index 08297651..658b71de 100644 --- a/VocaluxeLib/Songs/CLineBase.cs +++ b/VocaluxeLib/Songs/CLineBase.cs @@ -65,8 +65,8 @@ namespace VocaluxeLib.Songs { if (_Notes.Count == 0) return 0; - int min = _Notes.Max(note => note.Tone); - int max = _Notes.Min(note => note.Tone); + int min = _Notes.Min(note => note.Tone); + int max = _Notes.Max(note => note.Tone); return min - (max - min) / 4; } From 82b650416f6e8899be81df671f995893663b9853 Mon Sep 17 00:00:00 2001 From: Flamefire Date: Wed, 26 Feb 2014 00:09:00 +0100 Subject: [PATCH 08/38] Split CDecoder --- Vocaluxe/Lib/Video/Acinerella/CDecoder.cs | 352 ++---------------- .../Lib/Video/Acinerella/CDecoderThread.cs | 312 ++++++++++++++++ Vocaluxe/Vocaluxe.csproj | 3 +- 3 files changed, 346 insertions(+), 321 deletions(-) create mode 100644 Vocaluxe/Lib/Video/Acinerella/CDecoderThread.cs diff --git a/Vocaluxe/Lib/Video/Acinerella/CDecoder.cs b/Vocaluxe/Lib/Video/Acinerella/CDecoder.cs index 9591eaaa..a60359eb 100644 --- a/Vocaluxe/Lib/Video/Acinerella/CDecoder.cs +++ b/Vocaluxe/Lib/Video/Acinerella/CDecoder.cs @@ -27,19 +27,9 @@ 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; @@ -52,28 +42,21 @@ namespace Vocaluxe.Lib.Video.Acinerella 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; - public CDecoder() - { - _Thread = new Thread(_Execute); - _Framebuffer = new CFramebuffer(10); - } + private CDecoderThread _Thread; + + public CDecoder() {} public float Length { get; private set; } + public bool Loop { private get; set; } + + public bool Finished { get; private set; } + public bool Paused { set @@ -89,13 +72,9 @@ namespace Vocaluxe.Lib.Video.Acinerella } } - 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)) @@ -104,20 +83,38 @@ namespace Vocaluxe.Lib.Video.Acinerella _FileName = fileName; //Do this here as one may want to get the length afterwards! - if (!_DoOpen()) + IntPtr pInstance = _LoadFile(); + if (pInstance == IntPtr.Zero) return false; - _FileOpened = true; - _Thread.Priority = ThreadPriority.Normal; - _Thread.Name = Path.GetFileName(fileName); - _Thread.Start(); + _Thread = new CDecoderThread(Path.GetFileName(fileName), pInstance); return true; } + //Open the file and get the length. + private IntPtr _LoadFile() + { + try + { + IntPtr pInstance = CAcinerella.AcInit(); + CAcinerella.AcOpen2(pInstance, _FileName); + + var instance = (SACInstance)Marshal.PtrToStructure(pInstance, typeof(SACInstance)); + Length = instance.Info.Duration / 1000f; + bool ok = instance.Opened; + if (ok) + return pInstance; + } + catch (Exception) {} + CLog.LogError("Error opening video file: " + _FileName); + return IntPtr.Zero; + } + public void Close() { - _Terminated = true; + if (_Thread != null) + _Thread.Stop(); Length = 0; } @@ -160,290 +157,5 @@ namespace Vocaluxe.Lib.Video.Acinerella } 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..7e40b96f --- /dev/null +++ b/Vocaluxe/Lib/Video/Acinerella/CDecoderThread.cs @@ -0,0 +1,312 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; +using Vocaluxe.Base; +using VocaluxeLib.Draw; + +namespace Vocaluxe.Lib.Video.Acinerella +{ + class CDecoderThread + { + private readonly Thread _Thread; + private readonly Object _MutexFramebuffer = new Object(); + private bool isStarted; + + private IntPtr _Instance; // 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 _FrameDuration; // frame time in s + private int _Width; + private int _Height; + + private bool _Terminated; + private bool _FrameAvailable; + private bool _NoMoreFrames; + private readonly AutoResetEvent _EvWakeUp = new AutoResetEvent(false); + private bool _IsSleeping; + private int _WaitCount; + + public CDecoderThread(String name, IntPtr instance) + { + _Framebuffer = new CFramebuffer(10); + _Instance = instance; + _Thread = new Thread(_Execute) {Priority = ThreadPriority.Normal, Name = name}; + _Thread.Start(); + } + + public void Stop() + { + _Terminated = true; + } + + private bool _DoOpen() + { + 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): " + _Thread.Name); + _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 _Free() + { + if (_Videodecoder != IntPtr.Zero) + CAcinerella.AcFreeDecoder(_Videodecoder); + + if (_Instance != IntPtr.Zero) + { + CAcinerella.AcClose(_Instance); + CAcinerella.AcFree(_Instance); + } + } + + 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() + { + if (!_DoOpen()) + Stop(); + 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 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 " + _Thread.Name); + } + } + + if (!frameFinished) + { + try + { + frameFinished = CAcinerella.AcGetFrame(_Instance, _Videodecoder); + } + catch (Exception) + { + CLog.LogError("Error AcGetFrame " + _Thread.Name); + } + } + 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; + } + } +} \ No newline at end of file diff --git a/Vocaluxe/Vocaluxe.csproj b/Vocaluxe/Vocaluxe.csproj index 51c3fb35..380eb362 100644 --- a/Vocaluxe/Vocaluxe.csproj +++ b/Vocaluxe/Vocaluxe.csproj @@ -251,6 +251,7 @@ + @@ -484,4 +485,4 @@ --> - + \ No newline at end of file From 524599866271b53f715ac69ac8f532687188b0b5 Mon Sep 17 00:00:00 2001 From: Flamefire Date: Thu, 27 Feb 2014 20:28:16 +0100 Subject: [PATCH 09/38] Highly optimized video decoding still some problems with looping videos --- Vocaluxe/Lib/Video/Acinerella/CDecoder.cs | 157 +++--- .../Lib/Video/Acinerella/CDecoderThread.cs | 470 +++++++++++------- Vocaluxe/Lib/Video/Acinerella/CFramebuffer.cs | 74 ++- 3 files changed, 415 insertions(+), 286 deletions(-) diff --git a/Vocaluxe/Lib/Video/Acinerella/CDecoder.cs b/Vocaluxe/Lib/Video/Acinerella/CDecoder.cs index a60359eb..db94ad2c 100644 --- a/Vocaluxe/Lib/Video/Acinerella/CDecoder.cs +++ b/Vocaluxe/Lib/Video/Acinerella/CDecoder.cs @@ -18,9 +18,6 @@ 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 @@ -28,46 +25,54 @@ namespace Vocaluxe.Lib.Video.Acinerella class CDecoder { private readonly Stopwatch _LoopTimer = new Stopwatch(); - private readonly Object _MutexSyncSignals = new Object(); - private float _LastShownTime; // time if the last shown frame in s - - private float _Time; + private float _LastShownTime = -1f; // time if the last shown frame in s private float _Gap; - private float _Start; - private bool _Loop; - - private float _SetTime; - private float _SetGap; - private float _SetStart; - private bool _SetSkip; - - private float _SkipTime; // = Start + VideoGap - - private string _FileName; // current video file name private bool _Paused; + private float _LoopTime; private CDecoderThread _Thread; - - public CDecoder() {} - public float Length { get; private set; } - - public bool Loop { private get; set; } - public bool Finished { get; private set; } + public CDecoder() + { + Length = 0; + Finished = true; + } + + 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(); } } } @@ -80,35 +85,15 @@ namespace Vocaluxe.Lib.Video.Acinerella if (!File.Exists(fileName)) return false; - _FileName = fileName; - - //Do this here as one may want to get the length afterwards! - IntPtr pInstance = _LoadFile(); - if (pInstance == IntPtr.Zero) - return false; - - - _Thread = new CDecoderThread(Path.GetFileName(fileName), pInstance); - return true; - } - - //Open the file and get the length. - private IntPtr _LoadFile() - { - try + _Thread = new CDecoderThread(); + if (_Thread.LoadFile(fileName)) { - IntPtr pInstance = CAcinerella.AcInit(); - CAcinerella.AcOpen2(pInstance, _FileName); - - var instance = (SACInstance)Marshal.PtrToStructure(pInstance, typeof(SACInstance)); - Length = instance.Info.Duration / 1000f; - bool ok = instance.Opened; - if (ok) - return pInstance; + Length = _Thread.Length; + Finished = false; + return _Thread.Start(); } - catch (Exception) {} - CLog.LogError("Error opening video file: " + _FileName); - return IntPtr.Zero; + _Thread = null; + return false; } public void Close() @@ -116,45 +101,61 @@ namespace Vocaluxe.Lib.Video.Acinerella 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 + else + time += _Gap; + _Thread.SyncTime(time); + + if (Math.Abs(_LastShownTime - time) < 1f / 1000 && frame != null) //Check 1 ms difference { - lock (_MutexSyncSignals) - { - _SetTime = time; - } - } - else if (Math.Abs(_LastShownTime - time) < 1f / 1000 && frame != null) //Check 1 ms difference - { - videoTime = _LastShownTime; + videoTime = _LastShownTime - _Gap; return true; } - _UploadNewFrame(ref frame); - videoTime = _LastShownTime; + CDecoderThread.EFrameState state = _Thread.GetFrame(ref frame, ref time); + switch (state) + { + case CDecoderThread.EFrameState.EndFrame: + Finished = true; + videoTime = Length - _Gap; + break; + case CDecoderThread.EFrameState.ValidFrame: + _LastShownTime = time; + videoTime = time - _Gap; + break; + default: + videoTime = _LastShownTime - _Gap; + break; + } 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); return true; } } diff --git a/Vocaluxe/Lib/Video/Acinerella/CDecoderThread.cs b/Vocaluxe/Lib/Video/Acinerella/CDecoderThread.cs index 7e40b96f..2f25a86a 100644 --- a/Vocaluxe/Lib/Video/Acinerella/CDecoderThread.cs +++ b/Vocaluxe/Lib/Video/Acinerella/CDecoderThread.cs @@ -1,51 +1,244 @@ using System; -using System.Collections.Generic; -using System.Linq; +using System.IO; using System.Runtime.InteropServices; -using System.Text; 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 readonly Thread _Thread; - private readonly Object _MutexFramebuffer = new Object(); - private bool isStarted; + public enum EFrameState + { + ValidFrame, + InvalidFrame, + EndFrame + } - private IntPtr _Instance; // acinerella instance + private Thread _Thread; + + 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 + // 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 _EvPause = new AutoResetEvent(false); + private readonly AutoResetEvent _EvNoMoreFrames = new AutoResetEvent(false); private bool _IsSleeping; private int _WaitCount; - public CDecoderThread(String name, IntPtr instance) + public float Length { get; private set; } + public bool Loop { get; set; } + + public CDecoderThread() { _Framebuffer = new CFramebuffer(10); - _Instance = instance; - _Thread = new Thread(_Execute) {Priority = ThreadPriority.Normal, Name = name}; + } + + //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; + _EvPause.Set(); + _EvWakeUp.Set(); + _EvNoMoreFrames.Set(); } - private bool _DoOpen() + public void Pause() + { + if (_Paused) + return; + _EvPause.Reset(); + _Paused = true; + } + + public void Resume() + { + if (!_Paused) + return; + _Paused = false; + _EvPause.Set(); + } + + public void Skip(float time) + { + //TODO: 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 + _Framebuffer.Clear(); + + + _RequestTime = time; + _RequestSkip = true; + _EvNoMoreFrames.Set(); + } + + private CFramebuffer.CFrame _FindFrame(float now) + { + CFramebuffer.CFrame result = null; + float maxEnd = now - _FrameDuration * 2; //Get only frames younger than 2 + CFramebuffer.CFrame frame; + bool first = true; + _Framebuffer.ResetStack(); + while ((frame = _Framebuffer.Pop()) != null) + { + float frameEnd = frame.Time + _FrameDuration; + //Don't show frames that are shown during or after now + if (frameEnd >= now) + { + //All following frames are after that one -> BREAK + if (!first) + break; + //Well... Should be. Workaround: + CFramebuffer.CFrame nextFrame = _Framebuffer.Pop(); + if (nextFrame == null || nextFrame.Time > frame.Time) + break; + frame.SetRead(); //Discard wrong frame + frame = nextFrame; + //Replicate calculations + frameEnd = frame.Time + _FrameDuration; + if (frameEnd >= now) + break; + } + first = false; + //Get the last(newest) possible frame and skip the rest to force in-order showing + if (frameEnd <= maxEnd) + { + //Frame is to old -> Discard + frame.SetRead(); + } + else + { + maxEnd = frameEnd; + result = frame; + } + } + return result; + } + + //Time should be < Length + public void SyncTime(float time) + { + if (_Thread == null) + return; //Not initialized + while (time >= Length) + time -= Length; + if (_RequestTime - time >= 1f / 1000f) + { + //Jump back more than 1ms + //Will mostly happen in loops when looped through + Skip(time); + } + else if (time - _RequestTime >= 1f / 1000f) + { + //we were more than 1 ms to slow -> Jump forward + // ReSharper disable CompareOfFloatsByEqualityOperator + if (Loop && _RequestTime == 0f) + // ReSharper restore CompareOfFloatsByEqualityOperator + { + //Check if we had a loop + _Framebuffer.ResetStack(); + CFramebuffer.CFrame frame; + while ((frame = _Framebuffer.Pop()) != null) + { + if (frame.Time + _FrameDuration >= time) + return; + } + } + + _RequestTime = time; + } + } + + public EFrameState GetFrame(ref CTexture frame, ref float time) + { + EFrameState result; + CFramebuffer.CFrame curFrame = _FindFrame(time); + + if (curFrame != null) + { + CDraw.UpdateOrAddTexture(ref frame, _Width, _Height, curFrame.Data); + if (!_Paused) + curFrame.SetRead(); + time = curFrame.Time; + result = (frame != null) ? EFrameState.ValidFrame : EFrameState.InvalidFrame; + } + else + { + if (_NoMoreFrames && _Framebuffer.IsEmpty()) + result = EFrameState.EndFrame; + else + result = EFrameState.InvalidFrame; + } + if (_IsSleeping) + { + _IsSleeping = false; + _EvWakeUp.Set(); + } + return result; + } + + private bool _OpenVideoStream() { int videoStreamIndex; SACDecoder videodecoder; @@ -57,16 +250,12 @@ namespace Vocaluxe.Lib.Video.Acinerella } catch (Exception) { - CLog.LogError("Error opening video file (can't find decoder): " + _Thread.Name); - _Free(); + CLog.LogError("Error opening video file (can't find decoder): " + _FileName); return false; } if (videoStreamIndex < 0) - { - _Free(); return false; - } _Width = videodecoder.StreamInfo.VideoInfo.FrameWidth; _Height = videodecoder.StreamInfo.VideoInfo.FrameHeight; @@ -74,14 +263,12 @@ namespace Vocaluxe.Lib.Video.Acinerella 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; } + //Just call this if thread is not alive private void _Free() { if (_Videodecoder != IntPtr.Zero) @@ -94,50 +281,108 @@ namespace Vocaluxe.Lib.Video.Acinerella } } + // Skip to a given time (in s) private void _Skip() { - _SkipTime = _Start + _Gap; - - if (_SkipTime < 0) - _SkipTime = 0; + float skipTime = _RequestTime; + if (skipTime < 0 || skipTime >= Length) + skipTime = 0; try { - CAcinerella.AcSeek(_Videodecoder, -1, (Int64)(_SkipTime * 1000f)); + CAcinerella.AcSeek(_Videodecoder, -1, (Int64)(skipTime * 1000f)); } catch (Exception e) { CLog.LogError("Error seeking video file \"" + _FileName + "\": " + e.Message); } - _LastDecodedTime = _SkipTime; + _LastDecodedTime = skipTime; - lock (_MutexFramebuffer) + _FrameAvailable = false; + } + + private void _Decode() + { + const int minFrameDropCount = 4; + + if (_Paused || _NoMoreFrames) + return; + + float videoTime = _RequestTime; + float timeDifference = videoTime - _LastDecodedTime; + + bool dropFrame = timeDifference >= (minFrameDropCount - 1) * _FrameDuration; + + bool hasFrameDecoded = false; + if (dropFrame) { - _Framebuffer.Clear(); + try + { + var frameDropCount = (int)(timeDifference / _FrameDuration); + 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 = 0; + _Skip(); + } + else + _NoMoreFrames = true; + } + } + + private void _CopyDecodedFrameToBuffer() + { + var videodecoder = (SACDecoder)Marshal.PtrToStructure(_Videodecoder, typeof(SACDecoder)); + if (videodecoder.Buffer != IntPtr.Zero) + { + _LastDecodedTime = (float)videodecoder.Timecode; + _Framebuffer.Put(videodecoder.Buffer, _LastDecodedTime); + } _FrameAvailable = false; } private void _Execute() { - if (!_DoOpen()) + if (!_OpenVideoStream()) + { + _Free(); Stop(); + } + while (!_Terminated) { - bool skip; - lock (_MutexSyncSignals) + if (_Paused) + _EvPause.WaitOne(); + if (_NoMoreFrames) + _EvNoMoreFrames.WaitOne(); + if (_RequestSkip) { - _Time = _SetTime; - skip = _SetSkip; - _SetSkip = false; - _Gap = _SetGap; - _Start = _SetStart; - _Loop = Loop; - } - - if (skip) + _RequestSkip = false; + _NoMoreFrames = false; _Skip(); + } if (!_FrameAvailable) _Decode(); @@ -146,9 +391,9 @@ namespace Vocaluxe.Lib.Video.Acinerella { if (!_Framebuffer.IsFull()) { - _Copy(); + _CopyDecodedFrameToBuffer(); _WaitCount = 0; - Thread.Sleep(1); + Thread.Sleep(5); } else if (_WaitCount > 3) { @@ -165,148 +410,5 @@ namespace Vocaluxe.Lib.Video.Acinerella _Free(); } - - 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 " + _Thread.Name); - } - } - - if (!frameFinished) - { - try - { - frameFinished = CAcinerella.AcGetFrame(_Instance, _Videodecoder); - } - catch (Exception) - { - CLog.LogError("Error AcGetFrame " + _Thread.Name); - } - } - 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; - } } } \ No newline at end of file diff --git a/Vocaluxe/Lib/Video/Acinerella/CFramebuffer.cs b/Vocaluxe/Lib/Video/Acinerella/CFramebuffer.cs index b0c2704f..fe9a42a5 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,38 @@ namespace Vocaluxe.Lib.Video.Acinerella CFrame frame = _Frames[_Last]; Marshal.Copy(data, frame.Data, 0, _DataSize); frame.Time = time; - _Last = _Next(_Last); + _Last = _GetNextIndex(_Last); return true; } - public CFrame Get() + //Only call from reader thread + public void ResetStack() { - return IsEmpty() ? null : _Frames[_First]; + _Next = _First; } - public bool SetRead() + //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 (IsEmpty()) - return false; - _First = _Next(_First); - return true; + 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 From 9f9a0e7b3079b4e3bcc53c32b7a668396155eccf Mon Sep 17 00:00:00 2001 From: Flamefire Date: Sun, 9 Mar 2014 19:44:00 +0100 Subject: [PATCH 10/38] Fix race conditions Improve performance further --- Vocaluxe/Lib/Video/Acinerella/CDecoder.cs | 4 +- .../Lib/Video/Acinerella/CDecoderThread.cs | 192 ++++++++++-------- Vocaluxe/Lib/Video/Acinerella/CFramebuffer.cs | 7 +- 3 files changed, 112 insertions(+), 91 deletions(-) diff --git a/Vocaluxe/Lib/Video/Acinerella/CDecoder.cs b/Vocaluxe/Lib/Video/Acinerella/CDecoder.cs index db94ad2c..27c3caea 100644 --- a/Vocaluxe/Lib/Video/Acinerella/CDecoder.cs +++ b/Vocaluxe/Lib/Video/Acinerella/CDecoder.cs @@ -50,7 +50,7 @@ namespace Vocaluxe.Lib.Video.Acinerella _Thread.Loop = value; if (value) { - _LoopTime = _Thread._RequestTime; + _LoopTime = _Thread.RequestTime; _LoopTimer.Restart(); } } @@ -133,7 +133,7 @@ namespace Vocaluxe.Lib.Video.Acinerella videoTime = _LastShownTime - _Gap; return true; } - CDecoderThread.EFrameState state = _Thread.GetFrame(ref frame, ref time); + CDecoderThread.EFrameState state = _Thread.GetFrame(ref frame, _LastShownTime + _Gap, ref time); switch (state) { case CDecoderThread.EFrameState.EndFrame: diff --git a/Vocaluxe/Lib/Video/Acinerella/CDecoderThread.cs b/Vocaluxe/Lib/Video/Acinerella/CDecoderThread.cs index 2f25a86a..04781c4e 100644 --- a/Vocaluxe/Lib/Video/Acinerella/CDecoderThread.cs +++ b/Vocaluxe/Lib/Video/Acinerella/CDecoderThread.cs @@ -20,6 +20,7 @@ namespace Vocaluxe.Lib.Video.Acinerella } 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 @@ -28,7 +29,7 @@ namespace Vocaluxe.Lib.Video.Acinerella private float _LastDecodedTime; // time of last decoded frame // time of last requested frame aka current should-be position (_LastDecodedTime should be >=_RequestTime) //HAS to be < Length - public float _RequestTime { get; private set; } + public float RequestTime { get; private set; } private bool _Paused; private String _FileName; @@ -88,7 +89,7 @@ namespace Vocaluxe.Lib.Video.Acinerella CLog.LogError("Tried to start a video file that is already started: " + _FileName); return false; } - _RequestTime = 0f; + RequestTime = 0f; _Thread = new Thread(_Execute) {Priority = ThreadPriority.Normal, Name = Path.GetFileName(_FileName)}; _Thread.Start(); return true; @@ -118,102 +119,67 @@ namespace Vocaluxe.Lib.Video.Acinerella _EvPause.Set(); } + //Sets the position to the given time discarding all decoded frames public void Skip(float time) { - //TODO: Problem: This is not threadsave + //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 - _Framebuffer.Clear(); + //Fix: Use mutex (TODO: Check overhead) + lock (_BufferMutex) //Cover clear, RequestTime=, _RequestSkip= + { + _Framebuffer.Clear(); - - _RequestTime = time; - _RequestSkip = true; + RequestTime = time; + _RequestSkip = true; + } _EvNoMoreFrames.Set(); } - private CFramebuffer.CFrame _FindFrame(float now) + private CFramebuffer.CFrame _FindFrame(float lastTime, float now) { CFramebuffer.CFrame result = null; - float maxEnd = now - _FrameDuration * 2; //Get only frames younger than 2 CFramebuffer.CFrame frame; - bool first = true; _Framebuffer.ResetStack(); while ((frame = _Framebuffer.Pop()) != null) { float frameEnd = frame.Time + _FrameDuration; - //Don't show frames that are shown during or after now - if (frameEnd >= now) + if (!Loop || lastTime < now) { - //All following frames are after that one -> BREAK - if (!first) - break; - //Well... Should be. Workaround: - CFramebuffer.CFrame nextFrame = _Framebuffer.Pop(); - if (nextFrame == null || nextFrame.Time > frame.Time) - break; - frame.SetRead(); //Discard wrong frame - frame = nextFrame; - //Replicate calculations - frameEnd = frame.Time + _FrameDuration; - if (frameEnd >= now) - break; - } - first = false; - //Get the last(newest) possible frame and skip the rest to force in-order showing - if (frameEnd <= maxEnd) - { - //Frame is to old -> Discard - frame.SetRead(); + //Regular case: Frame has to be between last frame and now + if (frameEnd > now) + break; // Next frames are after this one + if (frame.Time < lastTime) + { + frame.SetRead(); //Frame is before last one, Discard + continue; + } } else { - maxEnd = frameEnd; - result = frame; + //Loop case: time rolled over -> Frame has to be after last one OR before now (which is after last one but rolled over) + if (frame.Time < lastTime && frameEnd > now) + break; } + //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 } return result; } - //Time should be < Length - public void SyncTime(float time) - { - if (_Thread == null) - return; //Not initialized - while (time >= Length) - time -= Length; - if (_RequestTime - time >= 1f / 1000f) - { - //Jump back more than 1ms - //Will mostly happen in loops when looped through - Skip(time); - } - else if (time - _RequestTime >= 1f / 1000f) - { - //we were more than 1 ms to slow -> Jump forward - // ReSharper disable CompareOfFloatsByEqualityOperator - if (Loop && _RequestTime == 0f) - // ReSharper restore CompareOfFloatsByEqualityOperator - { - //Check if we had a loop - _Framebuffer.ResetStack(); - CFramebuffer.CFrame frame; - while ((frame = _Framebuffer.Pop()) != null) - { - if (frame.Time + _FrameDuration >= time) - return; - } - } - - _RequestTime = time; - } - } - - public EFrameState GetFrame(ref CTexture frame, ref float time) + public EFrameState GetFrame(ref CTexture frame, float lastTime, ref float time) { EFrameState result; - CFramebuffer.CFrame curFrame = _FindFrame(time); + CFramebuffer.CFrame curFrame = _FindFrame(lastTime, time); if (curFrame != null) { @@ -238,15 +204,49 @@ namespace Vocaluxe.Lib.Video.Acinerella return result; } + //Time should be < Length + public void SyncTime(float time) + { + if (_Thread == null) + return; //Not initialized + while (time >= Length) + time -= Length; + if (RequestTime - time >= 1f / 1000f) + { + //Jump back more than 1ms + //Will mostly happen in loops when looped through + Skip(time); + } + else if (time - RequestTime >= 1f / 1000f) + { + //we were more than 1 ms to slow -> Jump forward + // ReSharper disable CompareOfFloatsByEqualityOperator + if (Loop && RequestTime == 0f) + // ReSharper restore CompareOfFloatsByEqualityOperator + { + //Check if we had a loop + _Framebuffer.ResetStack(); + CFramebuffer.CFrame frame; + while ((frame = _Framebuffer.Pop()) != null) + { + if (frame.Time + _FrameDuration >= time) + return; + } + } + + RequestTime = time; + } + } + private bool _OpenVideoStream() { int videoStreamIndex; - SACDecoder videodecoder; + SACDecoder decoder; try { _Videodecoder = CAcinerella.AcCreateVideoDecoder(_Instance); - videodecoder = (SACDecoder)Marshal.PtrToStructure(_Videodecoder, typeof(SACDecoder)); - videoStreamIndex = videodecoder.StreamIndex; + decoder = (SACDecoder)Marshal.PtrToStructure(_Videodecoder, typeof(SACDecoder)); + videoStreamIndex = decoder.StreamIndex; } catch (Exception) { @@ -257,11 +257,11 @@ namespace Vocaluxe.Lib.Video.Acinerella if (videoStreamIndex < 0) return false; - _Width = videodecoder.StreamInfo.VideoInfo.FrameWidth; - _Height = videodecoder.StreamInfo.VideoInfo.FrameHeight; + _Width = decoder.StreamInfo.VideoInfo.FrameWidth; + _Height = decoder.StreamInfo.VideoInfo.FrameHeight; - if (videodecoder.StreamInfo.VideoInfo.FramesPerSecond > 0) - _FrameDuration = 1f / (float)videodecoder.StreamInfo.VideoInfo.FramesPerSecond; + if (decoder.StreamInfo.VideoInfo.FramesPerSecond > 0) + _FrameDuration = 1f / (float)decoder.StreamInfo.VideoInfo.FramesPerSecond; _Framebuffer.Init(_Width * _Height * 4); _FrameAvailable = false; @@ -284,7 +284,7 @@ namespace Vocaluxe.Lib.Video.Acinerella // Skip to a given time (in s) private void _Skip() { - float skipTime = _RequestTime; + float skipTime = RequestTime; //Copy to variable to have consistent checks if (skipTime < 0 || skipTime >= Length) skipTime = 0; @@ -308,7 +308,7 @@ namespace Vocaluxe.Lib.Video.Acinerella if (_Paused || _NoMoreFrames) return; - float videoTime = _RequestTime; + float videoTime = RequestTime; float timeDifference = videoTime - _LastDecodedTime; bool dropFrame = timeDifference >= (minFrameDropCount - 1) * _FrameDuration; @@ -344,7 +344,7 @@ namespace Vocaluxe.Lib.Video.Acinerella { if (Loop) { - _RequestTime = 0; + RequestTime = 0; _Skip(); } else @@ -352,15 +352,21 @@ namespace Vocaluxe.Lib.Video.Acinerella } } - private void _CopyDecodedFrameToBuffer() + //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() { - var videodecoder = (SACDecoder)Marshal.PtrToStructure(_Videodecoder, typeof(SACDecoder)); - if (videodecoder.Buffer != IntPtr.Zero) + bool result; + var decoder = (SACDecoder)Marshal.PtrToStructure(_Videodecoder, typeof(SACDecoder)); + if (decoder.Buffer != IntPtr.Zero) { - _LastDecodedTime = (float)videodecoder.Timecode; - _Framebuffer.Put(videodecoder.Buffer, _LastDecodedTime); + _LastDecodedTime = (float)decoder.Timecode; + result = _Framebuffer.Put(decoder.Buffer, _LastDecodedTime); } + else + result = false; _FrameAvailable = false; + return result; } private void _Execute() @@ -387,13 +393,23 @@ namespace Vocaluxe.Lib.Video.Acinerella if (!_FrameAvailable) _Decode(); - if (_FrameAvailable) + //Bail out if we want to skip + if (!_RequestSkip && _FrameAvailable) { if (!_Framebuffer.IsFull()) { - _CopyDecodedFrameToBuffer(); + 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); + Thread.Sleep(5); //Sleep for a bit to give other threads an opportunity to run } else if (_WaitCount > 3) { diff --git a/Vocaluxe/Lib/Video/Acinerella/CFramebuffer.cs b/Vocaluxe/Lib/Video/Acinerella/CFramebuffer.cs index fe9a42a5..a7e9ea1b 100644 --- a/Vocaluxe/Lib/Video/Acinerella/CFramebuffer.cs +++ b/Vocaluxe/Lib/Video/Acinerella/CFramebuffer.cs @@ -97,10 +97,15 @@ namespace Vocaluxe.Lib.Video.Acinerella CFrame frame = _Frames[_Last]; Marshal.Copy(data, frame.Data, 0, _DataSize); frame.Time = time; - _Last = _GetNextIndex(_Last); return true; } + //Only call from writer thread after succesfull put + public void SetWritten() + { + _Last = _GetNextIndex(_Last); + } + //Only call from reader thread public void ResetStack() { From 24ca4edab77e08b81146cf338f13a8735fbaa390 Mon Sep 17 00:00:00 2001 From: Flamefire Date: Sun, 9 Mar 2014 19:49:06 +0100 Subject: [PATCH 11/38] Make Logfile more thread save --- Vocaluxe/Base/CLog.cs | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/Vocaluxe/Base/CLog.cs b/Vocaluxe/Base/CLog.cs index 6f87a74c..2dd153f0 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 Object _FileMutex = new Object(); public CLogFile(string fileName, string logName) { @@ -37,23 +38,31 @@ 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) From 90ba1188d35e6302136eb483d0ad6e36c156edac Mon Sep 17 00:00:00 2001 From: Flamefire Date: Sun, 9 Mar 2014 20:07:28 +0100 Subject: [PATCH 12/38] Add more log files to distinguish between classes of messages --- Vocaluxe/Base/CLog.cs | 24 ++++++++++++++++++++---- Vocaluxe/Base/CMain.cs | 10 ++++++++++ Vocaluxe/Base/CSettings.cs | 2 ++ VocaluxeLib/IBasic.cs | 2 ++ VocaluxeLib/Songs/CSongLoader.cs | 2 +- 5 files changed, 35 insertions(+), 5 deletions(-) diff --git a/Vocaluxe/Base/CLog.cs b/Vocaluxe/Base/CLog.cs index 2dd153f0..740d958e 100644 --- a/Vocaluxe/Base/CLog.cs +++ b/Vocaluxe/Base/CLog.cs @@ -28,7 +28,7 @@ namespace Vocaluxe.Base private readonly string _LogFileName; private readonly string _LogName; private StreamWriter _LogFile; - private Object _FileMutex = new Object(); + private readonly Object _FileMutex = new Object(); public CLogFile(string fileName, string logName) { @@ -94,6 +94,8 @@ 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; @@ -101,9 +103,11 @@ namespace Vocaluxe.Base public static void Init() { - _ErrorLog = new CLogFile(CSettings.FileErrorLog, "ErrorLog"); - _PerformanceLog = new CLogFile(CSettings.FilePerformanceLog, "PerformanceLog"); - _BenchmarkLog = new CLogFile(CSettings.FileBenchmarkLog, "BenchmarkLog"); + _ErrorLog = new CLogFile(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]; @@ -116,6 +120,8 @@ namespace Vocaluxe.Base _ErrorLog.Close(); _PerformanceLog.Close(); _BenchmarkLog.Close(); + _DebugLog.Close(); + _SongInfoLog.Close(); } #region LogError @@ -132,6 +138,16 @@ namespace Vocaluxe.Base } #endregion LogError + 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); + } + #region LogPerformance public static void LogPerformance(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..e9dd805d 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"; 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/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) From 5787839b95ed13db7413e07777568a18c6e80f75 Mon Sep 17 00:00:00 2001 From: Flamefire Date: Mon, 10 Mar 2014 20:04:03 +0100 Subject: [PATCH 13/38] Introduce class for error log --- Vocaluxe/Base/CLog.cs | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/Vocaluxe/Base/CLog.cs b/Vocaluxe/Base/CLog.cs index 740d958e..8afe6cd4 100644 --- a/Vocaluxe/Base/CLog.cs +++ b/Vocaluxe/Base/CLog.cs @@ -65,7 +65,7 @@ namespace Vocaluxe.Base } } - public void Add(string text) + public virtual void Add(string text) { if (_LogFile == null) _Open(); @@ -78,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; @@ -97,19 +110,17 @@ namespace Vocaluxe.Base 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, "Error-Log"); + _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(); @@ -127,12 +138,11 @@ namespace Vocaluxe.Base #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); } @@ -148,13 +158,11 @@ namespace Vocaluxe.Base _SongInfoLog.Add(text); } - #region LogPerformance public static void LogPerformance(string text) { _PerformanceLog.Add(text); _PerformanceLog.Add("-------------------------------"); } - #endregion LogPerformance #region LogBenchmark public static void StartBenchmark(int benchmarkNr, string text) From 5b478a185e87d1775e8b9d9e4e2cc27902f2d515 Mon Sep 17 00:00:00 2001 From: Flamefire Date: Mon, 10 Mar 2014 21:13:03 +0100 Subject: [PATCH 14/38] Remove pointless Timer Make GetPlayerColor more consistent --- Vocaluxe/Base/CTheme.cs | 13 ++----------- Vocaluxe/Screens/CScreenLoad.cs | 11 ----------- 2 files changed, 2 insertions(+), 22 deletions(-) diff --git a/Vocaluxe/Base/CTheme.cs b/Vocaluxe/Base/CTheme.cs index 52bbc631..42b1bf7e 100644 --- a/Vocaluxe/Base/CTheme.cs +++ b/Vocaluxe/Base/CTheme.cs @@ -789,14 +789,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 +817,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/Screens/CScreenLoad.cs b/Vocaluxe/Screens/CScreenLoad.cs index e5ccaae2..35ce9d38 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,7 +37,6 @@ 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 bool _IntroOutPlayed; @@ -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) @@ -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) @@ -201,8 +192,6 @@ namespace Vocaluxe.Screens public override void OnClose() { base.OnClose(); - _Timer.Stop(); - _Timer.Reset(); foreach (CVideoPlayer videoPlayer in _Intros) videoPlayer.Close(); From 070777eb68ef590ab53b1a890ab94586a59609ae Mon Sep 17 00:00:00 2001 From: Flamefire Date: Mon, 10 Mar 2014 21:13:28 +0100 Subject: [PATCH 15/38] Show the color of a player while selecting channels --- .../Ambient/Screens/ScreenOptionsRecord.xml | 66 +++++++++---------- .../Changelog_ScreenOptionsRecord.txt | 5 +- Vocaluxe/Screens/CScreenOptionsRecord.cs | 18 +++-- 3 files changed, 51 insertions(+), 38 deletions(-) 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/Screens/CScreenOptionsRecord.cs b/Vocaluxe/Screens/CScreenOptionsRecord.cs index 3d8bdbf8..6adc9bd5 100644 --- a/Vocaluxe/Screens/CScreenOptionsRecord.cs +++ b/Vocaluxe/Screens/CScreenOptionsRecord.cs @@ -37,7 +37,7 @@ namespace Vocaluxe.Screens // 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; @@ -53,6 +53,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"; @@ -77,7 +80,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}; @@ -248,8 +251,7 @@ namespace Vocaluxe.Screens _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)) + else if (CSound.RecordGetMaxVolume(player - 1) > 0.1f && CSound.RecordGetToneAbs(player - 1) % 12 == 9) { _DelayTest[i].Delay = _DelayTest[i].Timer.ElapsedMilliseconds; _DelayTest[i].Timer.Stop(); @@ -444,6 +446,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 +459,7 @@ namespace Vocaluxe.Screens CRecordDevice device = _Devices[_DeviceNr]; device.PlayerChannel1 = _SelectSlides[_SelectSlideRecordChannel1].Selection; device.PlayerChannel2 = _SelectSlides[_SelectSlideRecordChannel2].Selection; + _SetPlayerColors(); } private void _UpdateChannels() @@ -459,6 +468,7 @@ namespace Vocaluxe.Screens _SelectSlides[_SelectSlideRecordChannel2].Selection = _Devices[_DeviceNr].PlayerChannel2; _SaveMicConfig(); + _SetPlayerColors(); } private bool _CheckMicConfig() From 0a9c6e5cfedc0eb26c0dd532a5a8db01b702959b Mon Sep 17 00:00:00 2001 From: Flamefire Date: Tue, 11 Mar 2014 00:42:22 +0100 Subject: [PATCH 16/38] Make the Serverconfig request admin rights only if required --- ClientServerLib/ClientServerLib/CServer.cs | 10 +- Vocaluxe/Program.cs | 2 + WebserverInitalConfig/CConfigHttpApi.cs | 204 +++++++++++++----- WebserverInitalConfig/Program.cs | 58 +++-- .../WebserverInitalConfig.csproj | 3 - 5 files changed, 206 insertions(+), 71 deletions(-) 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/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/WebserverInitalConfig/CConfigHttpApi.cs b/WebserverInitalConfig/CConfigHttpApi.cs index 4bbd3ed9..fe184af4 100644 --- a/WebserverInitalConfig/CConfigHttpApi.cs +++ b/WebserverInitalConfig/CConfigHttpApi.cs @@ -15,6 +15,9 @@ // along with Vocaluxe. If not, see . #endregion +using System.Diagnostics; +using System.Security.Authentication; +using System.Security.Principal; using Security.Cryptography; using Security.Cryptography.X509Certificates; using System; @@ -26,34 +29,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 +95,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 +142,113 @@ 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; + foreach (INetFwAuthorizedApplication a in profile.AuthorizedApplications) + { + if (a.ProcessImageFileName == _ExePath) + return true; + } + return false; + } + + private bool _IsPortOpen(INetFwProfile profile) + { + NET_FW_IP_PROTOCOL_ protocol = _GetProtocol(); + + if (!profile.FirewallEnabled) + return true; + foreach (INetFwOpenPort p in profile.GloballyOpenPorts) + { + if (p.Protocol == protocol && p.Port == _Port) + return true; + } + return false; + } + + 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/Program.cs b/WebserverInitalConfig/Program.cs index 4b7ce630..a4f3a315 100644 --- a/WebserverInitalConfig/Program.cs +++ b/WebserverInitalConfig/Program.cs @@ -16,34 +16,64 @@ #endregion using System; +using System.Diagnostics; using System.IO; using System.Net; +using System.Net.Mime; +using System.Security.Authentication; using System.Security.Cryptography.X509Certificates; 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/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 From 44dceaed60791d1fa480bc56c236e481ae9356de Mon Sep 17 00:00:00 2001 From: Flamefire Date: Tue, 11 Mar 2014 20:30:07 +0100 Subject: [PATCH 17/38] Add names to all threads --- ClientServerLib/ClientServerLib/CDiscover.cs | 2 +- Vocaluxe/Lib/Sound/CDirectSoundRecord.cs | 2 +- Vocaluxe/Lib/Sound/CGstreamerSharpAudio.cs | 31 ++++++++++++++++---- Vocaluxe/Lib/Sound/COpenALPlay.cs | 2 +- Vocaluxe/Lib/Sound/CPortAudioPlay.cs | 2 +- 5 files changed, 29 insertions(+), 10 deletions(-) diff --git a/ClientServerLib/ClientServerLib/CDiscover.cs b/ClientServerLib/ClientServerLib/CDiscover.cs index 9dd5aa3d..ecff0173 100644 --- a/ClientServerLib/ClientServerLib/CDiscover.cs +++ b/ClientServerLib/ClientServerLib/CDiscover.cs @@ -73,7 +73,7 @@ namespace ServerLib return; _DiscoverRunning = true; - _DiscoverThread = new Thread(() => _Discover(Timeout)); + _DiscoverThread = new Thread(() => _Discover(Timeout)) {Name = "Client discover"}; _OnDiscovered = OnDiscovered; _DiscoverThread.Start(); } diff --git a/Vocaluxe/Lib/Sound/CDirectSoundRecord.cs b/Vocaluxe/Lib/Sound/CDirectSoundRecord.cs index 15fcc291..a769fb5e 100644 --- a/Vocaluxe/Lib/Sound/CDirectSoundRecord.cs +++ b/Vocaluxe/Lib/Sound/CDirectSoundRecord.cs @@ -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..84e2226c 100644 --- a/Vocaluxe/Lib/Sound/CGstreamerSharpAudio.cs +++ b/Vocaluxe/Lib/Sound/CGstreamerSharpAudio.cs @@ -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,9 +213,9 @@ 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; @@ -240,7 +240,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 +252,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 @@ -307,7 +324,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 +335,7 @@ namespace Vocaluxe.Lib.Sound { _Element.SetState(State.Null); _Element.Dispose(); + _Element = null; } } @@ -388,7 +406,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; diff --git a/Vocaluxe/Lib/Sound/COpenALPlay.cs b/Vocaluxe/Lib/Sound/COpenALPlay.cs index caecc663..67891ffb 100644 --- a/Vocaluxe/Lib/Sound/COpenALPlay.cs +++ b/Vocaluxe/Lib/Sound/COpenALPlay.cs @@ -416,7 +416,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) diff --git a/Vocaluxe/Lib/Sound/CPortAudioPlay.cs b/Vocaluxe/Lib/Sound/CPortAudioPlay.cs index 6cbf218b..985d936e 100644 --- a/Vocaluxe/Lib/Sound/CPortAudioPlay.cs +++ b/Vocaluxe/Lib/Sound/CPortAudioPlay.cs @@ -401,7 +401,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() From 668d72d3a7339ce397ca0f68e158eaa9514dd402 Mon Sep 17 00:00:00 2001 From: Flamefire Date: Tue, 11 Mar 2014 21:50:33 +0100 Subject: [PATCH 18/38] Make WiiMote consume less resources (do not run thread if not required) --- Vocaluxe/Lib/Input/CHIDAPI.cs | 12 +- Vocaluxe/Lib/Input/WiiMote/CWiiMote.cs | 17 +-- Vocaluxe/Lib/Input/WiiMote/WiiMoteLib.cs | 163 ++++++++--------------- 3 files changed, 68 insertions(+), 124 deletions(-) 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 From 76f491b347e141ad784afdf1001d725ad684f5d1 Mon Sep 17 00:00:00 2001 From: Flamefire Date: Tue, 11 Mar 2014 22:38:47 +0100 Subject: [PATCH 19/38] Formatting --- .../ClientServerLib/ICWebservice.cs | 28 ------------------- Vocaluxe/Lib/Sound/CDirectSoundRecord.cs | 2 +- 2 files changed, 1 insertion(+), 29 deletions(-) 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/Vocaluxe/Lib/Sound/CDirectSoundRecord.cs b/Vocaluxe/Lib/Sound/CDirectSoundRecord.cs index a769fb5e..4235f8ac 100644 --- a/Vocaluxe/Lib/Sound/CDirectSoundRecord.cs +++ b/Vocaluxe/Lib/Sound/CDirectSoundRecord.cs @@ -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) {Name="DirectSoundCapture",IsBackground = true}; + _CaptureThread = new Thread(_DoCapture) {Name = "DirectSoundCapture", IsBackground = true}; _Running = true; _CaptureThread.Start(); From 424cb826eda50334db524754a36e9b142c9e8ecf Mon Sep 17 00:00:00 2001 From: Flamefire Date: Tue, 11 Mar 2014 22:54:24 +0100 Subject: [PATCH 20/38] Fix crash if there are no songs in highscore --- Vocaluxe/Screens/CScreenHighscore.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Vocaluxe/Screens/CScreenHighscore.cs b/Vocaluxe/Screens/CScreenHighscore.cs index 411cd2cd..01848911 100644 --- a/Vocaluxe/Screens/CScreenHighscore.cs +++ b/Vocaluxe/Screens/CScreenHighscore.cs @@ -279,8 +279,13 @@ namespace Vocaluxe.Screens private void _ChangePos(int num) { - _Pos += num; - _Pos = _Pos.Clamp(0, _Scores[_Round].Count - 1); + if (_Scores[_Round].Count == 0) + _Pos = 0; + else + { + _Pos += num; + _Pos = _Pos.Clamp(0, _Scores[_Round].Count - 1); + } } private void _ChangeRound(int num) From 898819fcf5c9710e221457efa492d6770a757d16 Mon Sep 17 00:00:00 2001 From: Flamefire Date: Wed, 12 Mar 2014 09:41:34 +0100 Subject: [PATCH 21/38] Fix code issues (naming, unused stuff) --- Vocaluxe/Base/CConfig.cs | 8 +- Vocaluxe/Base/CGame.cs | 23 +++--- Vocaluxe/Base/CGraphics.cs | 3 - Vocaluxe/Base/CSettings.cs | 2 +- Vocaluxe/Base/CSongs.cs | 4 +- Vocaluxe/Base/CTheme.cs | 1 - Vocaluxe/Base/Server/CCommands.cs | 3 +- Vocaluxe/Base/Server/CVocaluxeServer.cs | 15 ++-- Vocaluxe/CProgrammHelper.cs | 4 - Vocaluxe/Lib/Playlist/CPlaylistFile.cs | 1 - Vocaluxe/Lib/Sound/CPortAudioPlay.cs | 4 +- Vocaluxe/Screens/CPopupScreenServerQR.cs | 6 -- .../Screens/CScreenOptionsVideoAdjustments.cs | 2 - Vocaluxe/Screens/CScreenScore.cs | 6 +- Vocaluxe/Website/css/style.css | 2 + VocaluxeLib/Enums.cs | 2 + VocaluxeLib/Extensions.cs | 3 +- VocaluxeLib/Menu/CBackground.cs | 9 +-- VocaluxeLib/Menu/CLyric.cs | 2 - VocaluxeLib/Menu/CMenu.cs | 1 - VocaluxeLib/Menu/CMenuPartyNameSelection.cs | 75 ++++++++++++++----- VocaluxeLib/Menu/CNameSelection.cs | 3 +- VocaluxeLib/Menu/SongMenu/CSongMenu.cs | 5 +- .../Menu/SongMenu/CSongMenuTileBoard.cs | 41 +++++----- VocaluxeLib/Profile/CAvatar.cs | 2 +- VocaluxeLib/Profile/CProfile.cs | 11 +-- VocaluxeLib/Songs/CLineBase.cs | 3 +- VocaluxeLib/Songs/CSong.cs | 2 +- VocaluxeLib/Songs/CSungNote.cs | 1 + VocaluxeLib/Songs/CVoice.cs | 4 +- WebserverInitalConfig/CConfigHttpApi.cs | 15 +--- WebserverInitalConfig/HttpApi.cs | 3 - WebserverInitalConfig/Program.cs | 2 - .../Properties/AssemblyInfo.cs | 1 - 34 files changed, 128 insertions(+), 141 deletions(-) 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/CGame.cs b/Vocaluxe/Base/CGame.cs index 238e314b..009e585f 100644 --- a/Vocaluxe/Base/CGame.cs +++ b/Vocaluxe/Base/CGame.cs @@ -208,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(); @@ -274,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; @@ -362,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); } @@ -416,15 +414,15 @@ namespace Vocaluxe.Base 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) @@ -436,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..92a2577b 100644 --- a/Vocaluxe/Base/CGraphics.cs +++ b/Vocaluxe/Base/CGraphics.cs @@ -404,9 +404,6 @@ namespace Vocaluxe.Base CConfig.BorderTop = 0; CConfig.BorderBottom = 0; break; - - default: - break; } CConfig.SaveConfig(); break; diff --git a/Vocaluxe/Base/CSettings.cs b/Vocaluxe/Base/CSettings.cs index e9dd805d..8d0c527b 100644 --- a/Vocaluxe/Base/CSettings.cs +++ b/Vocaluxe/Base/CSettings.cs @@ -104,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"; 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/CTheme.cs b/Vocaluxe/Base/CTheme.cs index 42b1bf7e..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; 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/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/CPortAudioPlay.cs b/Vocaluxe/Lib/Sound/CPortAudioPlay.cs index 985d936e..82af2e91 100644 --- a/Vocaluxe/Lib/Sound/CPortAudioPlay.cs +++ b/Vocaluxe/Lib/Sound/CPortAudioPlay.cs @@ -665,7 +665,7 @@ namespace Vocaluxe.Lib.Sound return -1; } - public bool Skip(float time) + public void Skip(float time) { lock (_LockSyncSignals) { @@ -673,8 +673,6 @@ namespace Vocaluxe.Lib.Sound _SetSkip = true; _Waiting = true; } - - return true; } #region Threading 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/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 ad079389..db70f56e 100644 --- a/Vocaluxe/Screens/CScreenScore.cs +++ b/Vocaluxe/Screens/CScreenScore.cs @@ -187,8 +187,8 @@ namespace Vocaluxe.Screens if (_SlideShowBGAvailable) _SlideShowBG.Draw(); else - base._DrawBG(); - base._DrawFG(); + _DrawBG(); + _DrawFG(); return true; } @@ -428,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/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/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/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/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 2a0bc348..6c972851 100644 --- a/VocaluxeLib/Songs/CLineBase.cs +++ b/VocaluxeLib/Songs/CLineBase.cs @@ -135,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/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/WebserverInitalConfig/CConfigHttpApi.cs b/WebserverInitalConfig/CConfigHttpApi.cs index fe184af4..38002df3 100644 --- a/WebserverInitalConfig/CConfigHttpApi.cs +++ b/WebserverInitalConfig/CConfigHttpApi.cs @@ -15,7 +15,6 @@ // along with Vocaluxe. If not, see . #endregion -using System.Diagnostics; using System.Security.Authentication; using System.Security.Principal; using Security.Cryptography; @@ -166,12 +165,7 @@ namespace WebserverInitalConfig { if (!profile.FirewallEnabled) return true; - foreach (INetFwAuthorizedApplication a in profile.AuthorizedApplications) - { - if (a.ProcessImageFileName == _ExePath) - return true; - } - return false; + return profile.AuthorizedApplications.Cast().Any(a => a.ProcessImageFileName == _ExePath); } private bool _IsPortOpen(INetFwProfile profile) @@ -180,12 +174,7 @@ namespace WebserverInitalConfig if (!profile.FirewallEnabled) return true; - foreach (INetFwOpenPort p in profile.GloballyOpenPorts) - { - if (p.Protocol == protocol && p.Port == _Port) - return true; - } - return false; + return profile.GloballyOpenPorts.Cast().Any(p => p.Protocol == protocol && p.Port == _Port); } private NET_FW_IP_PROTOCOL_ _GetProtocol() 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 a4f3a315..fc09dac1 100644 --- a/WebserverInitalConfig/Program.cs +++ b/WebserverInitalConfig/Program.cs @@ -19,9 +19,7 @@ using System; using System.Diagnostics; using System.IO; using System.Net; -using System.Net.Mime; using System.Security.Authentication; -using System.Security.Cryptography.X509Certificates; namespace WebserverInitalConfig { 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 From 58e05842ea2fc1b3fbf5d68f68970b5efb46f9a6 Mon Sep 17 00:00:00 2001 From: Flamefire Date: Wed, 12 Mar 2014 16:19:26 +0100 Subject: [PATCH 22/38] Actually pause video --- Vocaluxe/Base/CVideo.cs | 9 +++++++++ 1 file changed, 9 insertions(+) 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() From 00d80a6163e40ce4e4893aa7bb03a8f0b6c7e983 Mon Sep 17 00:00:00 2001 From: Flamefire Date: Wed, 12 Mar 2014 16:20:25 +0100 Subject: [PATCH 23/38] Only draw the current video --- Vocaluxe/Screens/CScreenLoad.cs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Vocaluxe/Screens/CScreenLoad.cs b/Vocaluxe/Screens/CScreenLoad.cs index 35ce9d38..4b6cf767 100644 --- a/Vocaluxe/Screens/CScreenLoad.cs +++ b/Vocaluxe/Screens/CScreenLoad.cs @@ -38,7 +38,7 @@ namespace Vocaluxe.Screens private Thread _SongLoaderThread; private bool _SkipIntro; - private int _CurrentIntroVideoNr; + private int _CurrentIntroVideo; private bool _IntroOutPlayed; private CVideoPlayer[] _Intros; @@ -106,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) @@ -182,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; @@ -217,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; } } From c6a22388d679c4eab7a7ab3bfccc080c926f7a48 Mon Sep 17 00:00:00 2001 From: Flamefire Date: Wed, 12 Mar 2014 16:20:54 +0100 Subject: [PATCH 24/38] Fix current frame not being removed in frame buffer --- Vocaluxe/Lib/Video/Acinerella/CFramebuffer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Vocaluxe/Lib/Video/Acinerella/CFramebuffer.cs b/Vocaluxe/Lib/Video/Acinerella/CFramebuffer.cs index a7e9ea1b..4ea6c543 100644 --- a/Vocaluxe/Lib/Video/Acinerella/CFramebuffer.cs +++ b/Vocaluxe/Lib/Video/Acinerella/CFramebuffer.cs @@ -126,7 +126,7 @@ namespace Vocaluxe.Lib.Video.Acinerella private void _SetRead(int index) { - if ((_First < index && (index < _Next || _Next < _First)) || (_Next < _First && index < _Next)) + if ((_First <= index && (index < _Next || _Next < _First)) || (_Next < _First && index < _Next)) _First = _GetNextIndex(index); } From cc35e7fd668e7a233481539286a7c280f7767664 Mon Sep 17 00:00:00 2001 From: Flamefire Date: Wed, 12 Mar 2014 16:25:33 +0100 Subject: [PATCH 25/38] Make loops smooth and decoder more robust --- Vocaluxe/Lib/Video/Acinerella/CDecoder.cs | 29 ++-- .../Lib/Video/Acinerella/CDecoderThread.cs | 126 ++++++++++-------- 2 files changed, 75 insertions(+), 80 deletions(-) diff --git a/Vocaluxe/Lib/Video/Acinerella/CDecoder.cs b/Vocaluxe/Lib/Video/Acinerella/CDecoder.cs index 27c3caea..743d5747 100644 --- a/Vocaluxe/Lib/Video/Acinerella/CDecoder.cs +++ b/Vocaluxe/Lib/Video/Acinerella/CDecoder.cs @@ -26,7 +26,6 @@ namespace Vocaluxe.Lib.Video.Acinerella { private readonly Stopwatch _LoopTimer = new Stopwatch(); - private float _LastShownTime = -1f; // time if the last shown frame in s private float _Gap; private bool _Paused; private float _LoopTime; @@ -128,26 +127,12 @@ namespace Vocaluxe.Lib.Video.Acinerella time += _Gap; _Thread.SyncTime(time); - if (Math.Abs(_LastShownTime - time) < 1f / 1000 && frame != null) //Check 1 ms difference - { - videoTime = _LastShownTime - _Gap; - return true; - } - CDecoderThread.EFrameState state = _Thread.GetFrame(ref frame, _LastShownTime + _Gap, ref time); - switch (state) - { - case CDecoderThread.EFrameState.EndFrame: - Finished = true; - videoTime = Length - _Gap; - break; - case CDecoderThread.EFrameState.ValidFrame: - _LastShownTime = time; - videoTime = time - _Gap; - break; - default: - videoTime = _LastShownTime - _Gap; - break; - } + bool finished; + _Thread.GetFrame(ref frame, ref time, out finished); + videoTime = time - _Gap; + + if (finished) //Only set, not reset + Finished = true; return frame != null; } @@ -156,6 +141,8 @@ namespace Vocaluxe.Lib.Video.Acinerella Finished = false; _Gap = gap; _Thread.Skip(start + gap); + if (Loop) + Loop = true; //Reset loop (timer) return true; } } diff --git a/Vocaluxe/Lib/Video/Acinerella/CDecoderThread.cs b/Vocaluxe/Lib/Video/Acinerella/CDecoderThread.cs index 04781c4e..522e7fc7 100644 --- a/Vocaluxe/Lib/Video/Acinerella/CDecoderThread.cs +++ b/Vocaluxe/Lib/Video/Acinerella/CDecoderThread.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics; using System.IO; using System.Runtime.InteropServices; using System.Threading; @@ -12,12 +13,7 @@ namespace Vocaluxe.Lib.Video.Acinerella //Most others are to be called by this thread (_Thread instance) only! class CDecoderThread { - public enum EFrameState - { - ValidFrame, - InvalidFrame, - EndFrame - } + private const float _LoopedRequestTime = -0.001f; //Magic const to detect if decoder looped automaticly private Thread _Thread; private readonly Object _BufferMutex = new Object(); @@ -27,6 +23,7 @@ namespace Vocaluxe.Lib.Video.Acinerella 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; } @@ -42,7 +39,6 @@ namespace Vocaluxe.Lib.Video.Acinerella private bool _FrameAvailable; private bool _NoMoreFrames; private readonly AutoResetEvent _EvWakeUp = new AutoResetEvent(false); - private readonly AutoResetEvent _EvPause = new AutoResetEvent(false); private readonly AutoResetEvent _EvNoMoreFrames = new AutoResetEvent(false); private bool _IsSleeping; private int _WaitCount; @@ -53,6 +49,7 @@ namespace Vocaluxe.Lib.Video.Acinerella 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. @@ -98,7 +95,6 @@ namespace Vocaluxe.Lib.Video.Acinerella public void Stop() { _Terminated = true; - _EvPause.Set(); _EvWakeUp.Set(); _EvNoMoreFrames.Set(); } @@ -107,7 +103,6 @@ namespace Vocaluxe.Lib.Video.Acinerella { if (_Paused) return; - _EvPause.Reset(); _Paused = true; } @@ -116,7 +111,6 @@ namespace Vocaluxe.Lib.Video.Acinerella if (!_Paused) return; _Paused = false; - _EvPause.Set(); } //Sets the position to the given time discarding all decoded frames @@ -131,37 +125,37 @@ namespace Vocaluxe.Lib.Video.Acinerella 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 lastTime, float now) + 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; - if (!Loop || lastTime < now) + //float frameEnd = frame.Time + _FrameDuration; + float frameTime = frame.Time; + + if (frameTime > now) { - //Regular case: Frame has to be between last frame and now - if (frameEnd > now) - break; // Next frames are after this one - if (frame.Time < lastTime) - { - frame.SetRead(); //Frame is before last one, Discard - continue; - } + //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 } - else + // ReSharper disable CompareOfFloatsByEqualityOperator + else if (Loop && RequestTime == _LoopedRequestTime) + // ReSharper restore CompareOfFloatsByEqualityOperator { - //Loop case: time rolled over -> Frame has to be after last one OR before now (which is after last one but rolled over) - if (frame.Time < lastTime && frameEnd > now) - break; + //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) @@ -171,36 +165,49 @@ namespace Vocaluxe.Lib.Video.Acinerella } result = frame; if (_Paused) - break; //Just get 1 frame if paused + break; //Just get 1 frame if paused otherwise a paused movie could move a bit } return result; } - public EFrameState GetFrame(ref CTexture frame, float lastTime, ref float time) + /// + /// 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) { - EFrameState result; - CFramebuffer.CFrame curFrame = _FindFrame(lastTime, time); - - if (curFrame != null) + bool result; + if (Math.Abs(_LastShownTime - time) < _FrameDuration && frame != null) //Check 1 frame difference { - CDraw.UpdateOrAddTexture(ref frame, _Width, _Height, curFrame.Data); - if (!_Paused) - curFrame.SetRead(); - time = curFrame.Time; - result = (frame != null) ? EFrameState.ValidFrame : EFrameState.InvalidFrame; + time = _LastShownTime; + result = false; } else { - if (_NoMoreFrames && _Framebuffer.IsEmpty()) - result = EFrameState.EndFrame; + 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 = EFrameState.InvalidFrame; - } - if (_IsSleeping) - { - _IsSleeping = false; - _EvWakeUp.Set(); + result = false; + + if (_IsSleeping) + { + _IsSleeping = false; + _EvWakeUp.Set(); + } } + finished = _NoMoreFrames && _Framebuffer.IsEmpty(); + return result; } @@ -209,22 +216,22 @@ namespace Vocaluxe.Lib.Video.Acinerella { if (_Thread == null) return; //Not initialized - while (time >= Length) - time -= Length; - if (RequestTime - time >= 1f / 1000f) + + if (RequestTime - time >= _FrameDuration) { - //Jump back more than 1ms - //Will mostly happen in loops when looped through + //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 >= 1f / 1000f) + else if (time - RequestTime >= _FrameDuration) { - //we were more than 1 ms to slow -> Jump forward + //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 == 0f) + if (Loop && RequestTime == _LoopedRequestTime) // ReSharper restore CompareOfFloatsByEqualityOperator { - //Check if we had a loop + //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) @@ -232,6 +239,9 @@ namespace Vocaluxe.Lib.Video.Acinerella 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; @@ -305,7 +315,7 @@ namespace Vocaluxe.Lib.Video.Acinerella { const int minFrameDropCount = 4; - if (_Paused || _NoMoreFrames) + if (_NoMoreFrames) return; float videoTime = RequestTime; @@ -344,7 +354,7 @@ namespace Vocaluxe.Lib.Video.Acinerella { if (Loop) { - RequestTime = 0; + RequestTime = _LoopedRequestTime; _Skip(); } else @@ -379,8 +389,6 @@ namespace Vocaluxe.Lib.Video.Acinerella while (!_Terminated) { - if (_Paused) - _EvPause.WaitOne(); if (_NoMoreFrames) _EvNoMoreFrames.WaitOne(); if (_RequestSkip) @@ -418,7 +426,7 @@ namespace Vocaluxe.Lib.Video.Acinerella } else { - Thread.Sleep((int)((_Framebuffer.Size - 2) * _FrameDuration * 1000)); + Thread.Sleep((int)(_Framebuffer.Size * _FrameDuration * 1000 / 2)); _WaitCount++; } } From 26564874e94ec621bf8774d0b38414800bc76679 Mon Sep 17 00:00:00 2001 From: Flamefire Date: Wed, 12 Mar 2014 16:43:03 +0100 Subject: [PATCH 26/38] Improve skipping --- Vocaluxe/Lib/Video/Acinerella/CDecoderThread.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Vocaluxe/Lib/Video/Acinerella/CDecoderThread.cs b/Vocaluxe/Lib/Video/Acinerella/CDecoderThread.cs index 522e7fc7..2b254b98 100644 --- a/Vocaluxe/Lib/Video/Acinerella/CDecoderThread.cs +++ b/Vocaluxe/Lib/Video/Acinerella/CDecoderThread.cs @@ -1,5 +1,4 @@ using System; -using System.Diagnostics; using System.IO; using System.Runtime.InteropServices; using System.Threading; @@ -328,7 +327,9 @@ namespace Vocaluxe.Lib.Video.Acinerella { try { - var frameDropCount = (int)(timeDifference / _FrameDuration); + 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) From 45e480785dccb4b8a2f5da24640964b7577063d3 Mon Sep 17 00:00:00 2001 From: Flamefire Date: Wed, 12 Mar 2014 18:42:45 +0100 Subject: [PATCH 27/38] Optimize tone detection (40% faster now) --- Vocaluxe/Base/CSound.cs | 233 +++++++++-------------- Vocaluxe/Lib/Sound/CDirectSoundRecord.cs | 2 +- Vocaluxe/Lib/Sound/CPortAudioRecord.cs | 2 +- 3 files changed, 89 insertions(+), 148 deletions(-) diff --git a/Vocaluxe/Base/CSound.cs b/Vocaluxe/Base/CSound.cs index 7df51ad7..f849afe7 100644 --- a/Vocaluxe/Base/CSound.cs +++ b/Vocaluxe/Base/CSound.cs @@ -205,26 +205,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() @@ -317,117 +312,66 @@ namespace Vocaluxe.Base class CBuffer : IDisposable { private const double _BaseToneFreq = 65.4064; - private const int _NumHalfTones = 47; + public const int NumHalfTones = 17; - private readonly float[] _ToneWeigth; - private Int16[] _AnalysisBuffer = new Int16[4096]; - private readonly Object _AnalysisBufferLock = new Object(); + 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 bool _ToneValid; - private int _Tone; - private int _ToneAbs; private double _MaxVolume; private bool _NewSamples; - private MemoryStream _Stream; // full buffer + 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; - _Stream = new MemoryStream(); - _NewSamples = false; + ToneWeigth = new float[NumHalfTones]; + for (int i = 0; i < ToneWeigth.Length; i++) + ToneWeigth[i] = 0.99f; } - public int NumHalfTones + static CBuffer() { - get { return _NumHalfTones; } - } - - public int ToneAbs - { - get + 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++) { - lock (_AnalysisBufferLock) - { - return _ToneAbs; - } + double freq = _BaseToneFreq * Math.Pow(halftoneBase, toneIndex); + _SamplesPerPeriodPerTone[toneIndex] = (int)Math.Round(44100.0 / freq); // samples in one period } } - public int Tone - { - get - { - lock (_AnalysisBufferLock) - { - return _Tone; - } - } - set - { - lock (_AnalysisBufferLock) - { - _Tone = value; - } - } - } + public int ToneAbs { get; private set; } + + public int Tone { get; set; } public float MaxVolume { - get - { - lock (_AnalysisBufferLock) - { - return (float)_MaxVolume; - } - } + get { return (float)_MaxVolume; } } - public bool ToneValid - { - get - { - lock (_AnalysisBufferLock) - { - return _ToneValid; - } - } - } + public bool ToneValid { get; private set; } - public long Length - { - get { return _Stream.Length; } - } - - public byte[] Buffer - { - get { return _Stream.ToArray(); } - } - - public float[] ToneWeigth - { - get - { - lock (_AnalysisBufferLock) - { - return _ToneWeigth; - } - } - } + public float[] ToneWeigth { get; private set; } public void Reset() { - _Stream.SetLength(0L); - _AnalysisBuffer = new Int16[_AnalysisBuffer.Length]; - _ToneValid = false; - _ToneAbs = 0; - _Tone = 0; - _NewSamples = false; + lock (_Stream) + { + _Stream.SetLength(0L); + _NewSamples = false; + } + ToneValid = false; + ToneAbs = 0; + Tone = 0; } - public void Add(byte[] bytes) + private void _Add(byte[] bytes) { _Stream.Write(bytes, 0, bytes.Length); } @@ -440,9 +384,9 @@ namespace Vocaluxe.Base // voice passthrough (send data to playback-device) //if (assigned(fVoiceStream)) then //fVoiceStream.WriteData(Buffer, BufferSize); - lock (_AnalysisBufferLock) + lock (_Stream) { - Add(buffer); + _Add(buffer); _NewSamples = true; } } @@ -452,67 +396,67 @@ namespace Vocaluxe.Base if (!_NewSamples) return; - lock (_AnalysisBufferLock) + lock (_Stream) { - int len = _AnalysisBuffer.Length * 2; - if (_Stream.Length >= len) + if (_Stream.Length >= _AnalysisByteBufLen) { - 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); - } + _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 - _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; - } + _FindMaxVolume(); - _AnalyzeByAutocorrelation(_MaxVolume >= 0.02f); + if (MaxVolume >= 0.02) + _AnalyzeByAutocorrelation(); + else + ToneValid = false; } catch (Exception) {} } - private void _AnalyzeByAutocorrelation(bool valid) + private void _FindMaxVolume() { - if (!valid) + short maxVolume = 0; + for (int i = 0; i < _AnalysisBuffer.Length / 4; i++) { - _ToneValid = false; - return; + 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; + } - const double halftoneBase = 1.05946309436; // 2^(1/12) -> HalftoneBase^12 = 2 (one octave) - + private void _AnalyzeByAutocorrelation() + { // 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++) + for (int toneIndex = 0; toneIndex < NumHalfTones; toneIndex++) { - double curFreq = _BaseToneFreq * Math.Pow(halftoneBase, toneIndex); - double curWeight = _AnalyzeAutocorrelationFreq(curFreq); + double curWeight = _AnalyzeAutocorrelationTone(toneIndex); if (curWeight > maxWeight) { @@ -523,42 +467,39 @@ namespace Vocaluxe.Base if (curWeight < minWeight) minWeight = curWeight; - weigth[toneIndex] = (float)curWeight; + _TmpWeight[toneIndex] = (float)curWeight; } if (maxWeight - minWeight > 0.01) { - for (int i = 0; i < weigth.Length; i++) - _ToneWeigth[i] = weigth[i]; + Array.Copy(_TmpWeight, ToneWeigth, NumHalfTones); - _ToneAbs = maxTone; - _Tone = maxTone % 12; - _ToneValid = true; + ToneAbs = maxTone; + Tone = maxTone % 12; + ToneValid = true; } else - _ToneValid = false; + ToneValid = false; } - private double _AnalyzeAutocorrelationFreq(double freq) + private double _AnalyzeAutocorrelationTone(int tone) { - 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 + int samplesPerPeriod = _SamplesPerPeriodPerTone[tone]; // samples in one period - double accumDist = 0.0; // accumulated distances + int accumDist = 0; // accumulated distances // compare correlating samples - while (correlatingSampleIndex < _AnalysisBuffer.Length) + 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) 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; + // 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; - sampleIndex++; - correlatingSampleIndex++; } - return 1 - accumDist / _AnalysisBuffer.Length; + return 1.0 - (double)accumDist / Int16.MaxValue / _AnalysisBufLen; } public void Dispose() diff --git a/Vocaluxe/Lib/Sound/CDirectSoundRecord.cs b/Vocaluxe/Lib/Sound/CDirectSoundRecord.cs index 4235f8ac..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) 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) From 88364ce64bb4631bc04a9cf24e8320810738bf7c Mon Sep 17 00:00:00 2001 From: Flamefire Date: Fri, 14 Mar 2014 00:27:42 +0100 Subject: [PATCH 28/38] Fix PlaySound (Length not gotten if prescan off) Add fade option to PlaySound --- Vocaluxe/Base/CSound.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Vocaluxe/Base/CSound.cs b/Vocaluxe/Base/CSound.cs index f849afe7..7dfe5840 100644 --- a/Vocaluxe/Base/CSound.cs +++ b/Vocaluxe/Base/CSound.cs @@ -181,7 +181,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 +189,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 From 10ecc361e2b259b85a38fa0b5448117e618a109d Mon Sep 17 00:00:00 2001 From: Flamefire Date: Fri, 14 Mar 2014 00:28:03 +0100 Subject: [PATCH 29/38] Make own class for Record-Delay testing fixing some bugs --- Vocaluxe/Screens/CScreenOptionsRecord.cs | 158 ++++++++++++++--------- 1 file changed, 95 insertions(+), 63 deletions(-) diff --git a/Vocaluxe/Screens/CScreenOptionsRecord.cs b/Vocaluxe/Screens/CScreenOptionsRecord.cs index 6adc9bd5..faea5180 100644 --- a/Vocaluxe/Screens/CScreenOptionsRecord.cs +++ b/Vocaluxe/Screens/CScreenOptionsRecord.cs @@ -15,6 +15,7 @@ // along with Vocaluxe. If not, see . #endregion +using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; @@ -26,10 +27,93 @@ using VocaluxeLib.Menu; namespace Vocaluxe.Screens { - struct SDelayTest + class CDelayTest { - public Stopwatch Timer; - public float Delay; + 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 = new SDelayChannel[2]; + public readonly int[] Delays = new int[2]; + + 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; + Console.WriteLine("Vol=" + CSound.RecordGetMaxVolume(0) + " Tone=" + CSound.RecordGetTone(0) + " Valid=" + CSound.RecordToneValid(0)); + 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(); + } + } } class CScreenOptionsRecord : CMenu @@ -40,7 +124,6 @@ namespace Vocaluxe.Screens get { return 4; } } - private const float _MaxDelayTime = 1f; private const string _SelectSlideRecordDevices = "SelectSlideRecordDevices"; private const string _SelectSlideRecordChannel1 = "SelectSlideRecordChannel1"; @@ -68,9 +151,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(); public override void Init() { @@ -224,46 +305,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) % 12 == 9) - { - _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].ToString("000") + " ms"; + _Texts[_TextDelayChannel2].Text = _DelayTest.Delays[1].ToString("000") + " ms"; } - if (_CheckMicConfig()) { _ChannelEnergy[0] = 0f; @@ -327,21 +375,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() @@ -393,7 +429,7 @@ namespace Vocaluxe.Screens base.OnClose(); CSound.RecordStop(); - _DelayTest = null; + _DelayTest.Reset(); CBackgroundMusic.Disabled = false; } @@ -505,11 +541,7 @@ namespace Vocaluxe.Screens { _SaveMicConfig(); - if (_DelayTest == null) - return; - - _DelaySound = CSound.PlaySound(ESounds.T440); - _DelayTestRunning = true; + _DelayTest.Start(new int[] {_SelectSlides[_SelectSlideRecordChannel1].Selection - 1, _SelectSlides[_SelectSlideRecordChannel2].Selection - 1}); } private void _GetFirstConfiguredRecordDevice(ref int device) From 5270d570d5b02bfd0cae240654c27739a401900d Mon Sep 17 00:00:00 2001 From: Flamefire Date: Fri, 14 Mar 2014 00:36:42 +0100 Subject: [PATCH 30/38] Split classes from CSound.cs to separate files (1 class/file) and move to Lib/Sound (where they belong) --- Vocaluxe/Base/CSound.cs | 361 ------------------------------- Vocaluxe/Lib/Sound/CBuffer.cs | 209 ++++++++++++++++++ Vocaluxe/Lib/Sound/CPt1.cs | 83 +++++++ Vocaluxe/Lib/Sound/CSyncTimer.cs | 81 +++++++ Vocaluxe/Vocaluxe.csproj | 3 + 5 files changed, 376 insertions(+), 361 deletions(-) create mode 100644 Vocaluxe/Lib/Sound/CBuffer.cs create mode 100644 Vocaluxe/Lib/Sound/CPt1.cs create mode 100644 Vocaluxe/Lib/Sound/CSyncTimer.cs diff --git a/Vocaluxe/Base/CSound.cs b/Vocaluxe/Base/CSound.cs index 7dfe5840..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; @@ -311,364 +310,4 @@ namespace Vocaluxe.Base } #endregion Record } - - 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); - } - } - - 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/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/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/Vocaluxe.csproj b/Vocaluxe/Vocaluxe.csproj index 380eb362..c08199fc 100644 --- a/Vocaluxe/Vocaluxe.csproj +++ b/Vocaluxe/Vocaluxe.csproj @@ -212,11 +212,14 @@ + + + From a8cfbea1aaaa757759f0e2cbbe31caf9b479d3cb Mon Sep 17 00:00:00 2001 From: Flamefire Date: Fri, 14 Mar 2014 00:49:04 +0100 Subject: [PATCH 31/38] Add channelNum to DelayTest Schow ??? for unknown delays Remove debug output --- Vocaluxe/Screens/CScreenOptionsRecord.cs | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/Vocaluxe/Screens/CScreenOptionsRecord.cs b/Vocaluxe/Screens/CScreenOptionsRecord.cs index faea5180..5a35d6b6 100644 --- a/Vocaluxe/Screens/CScreenOptionsRecord.cs +++ b/Vocaluxe/Screens/CScreenOptionsRecord.cs @@ -15,7 +15,6 @@ // along with Vocaluxe. If not, see . #endregion -using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; @@ -40,8 +39,16 @@ namespace Vocaluxe.Screens private readonly Stopwatch _Timer = new Stopwatch(); private int _Stream = -1; - private readonly SDelayChannel[] _DelaysChannel = new SDelayChannel[2]; - public readonly int[] Delays = new int[2]; + 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) { @@ -90,7 +97,7 @@ namespace Vocaluxe.Screens } if (!_Timer.IsRunning) return; - Console.WriteLine("Vol=" + CSound.RecordGetMaxVolume(0) + " Tone=" + CSound.RecordGetTone(0) + " Valid=" + CSound.RecordToneValid(0)); + bool isActive = false; if (_Timer.ElapsedMilliseconds <= _MaxDelayTime) { @@ -151,7 +158,7 @@ namespace Vocaluxe.Screens private ReadOnlyCollection _Devices; private int _DeviceNr; - private readonly CDelayTest _DelayTest = new CDelayTest(); + private readonly CDelayTest _DelayTest = new CDelayTest(2); public override void Init() { @@ -308,8 +315,8 @@ namespace Vocaluxe.Screens if (_DelayTest.Running) { _DelayTest.Update(); - _Texts[_TextDelayChannel1].Text = _DelayTest.Delays[0].ToString("000") + " ms"; - _Texts[_TextDelayChannel2].Text = _DelayTest.Delays[1].ToString("000") + " ms"; + _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()) @@ -540,7 +547,7 @@ namespace Vocaluxe.Screens private void _TestDelay() { _SaveMicConfig(); - + _DelayTest.Reset(); _DelayTest.Start(new int[] {_SelectSlides[_SelectSlideRecordChannel1].Selection - 1, _SelectSlides[_SelectSlideRecordChannel2].Selection - 1}); } From 3f5d5fc001b37da41f8262ed5c20ce2105d4c7ed Mon Sep 17 00:00:00 2001 From: Flamefire Date: Fri, 14 Mar 2014 00:50:13 +0100 Subject: [PATCH 32/38] Move CDelayTest to a file in Lib/Sound --- Vocaluxe/Lib/Sound/CDelayTest.cs | 102 +++++++++++++++++++++++ Vocaluxe/Screens/CScreenOptionsRecord.cs | 98 ---------------------- Vocaluxe/Vocaluxe.csproj | 1 + 3 files changed, 103 insertions(+), 98 deletions(-) create mode 100644 Vocaluxe/Lib/Sound/CDelayTest.cs 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/Screens/CScreenOptionsRecord.cs b/Vocaluxe/Screens/CScreenOptionsRecord.cs index 5a35d6b6..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,103 +25,6 @@ using VocaluxeLib.Menu; namespace Vocaluxe.Screens { - 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(); - } - } - } - class CScreenOptionsRecord : CMenu { // Version number for theme files. Increment it, if you've changed something on the theme files! diff --git a/Vocaluxe/Vocaluxe.csproj b/Vocaluxe/Vocaluxe.csproj index c08199fc..1b5d5b87 100644 --- a/Vocaluxe/Vocaluxe.csproj +++ b/Vocaluxe/Vocaluxe.csproj @@ -256,6 +256,7 @@ + From f5cca32dd8dffb1e7f1c7198f5b6d2ee4a2148de Mon Sep 17 00:00:00 2001 From: Flamefire Date: Fri, 14 Mar 2014 00:51:50 +0100 Subject: [PATCH 33/38] Bump version to *.83 (Big changes, should do that more frequently) --- Vocaluxe/Properties/AssemblyInfo.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 From 636dbf0f961e9b4b808ae0d2e9b4bf8c1bd0596b Mon Sep 17 00:00:00 2001 From: Flamefire Date: Fri, 14 Mar 2014 15:50:56 +0100 Subject: [PATCH 34/38] Fix GStreamer# bug with loop Sounds --- Vocaluxe/Lib/Sound/CGstreamerSharpAudio.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Vocaluxe/Lib/Sound/CGstreamerSharpAudio.cs b/Vocaluxe/Lib/Sound/CGstreamerSharpAudio.cs index 84e2226c..da0e2ca0 100644 --- a/Vocaluxe/Lib/Sound/CGstreamerSharpAudio.cs +++ b/Vocaluxe/Lib/Sound/CGstreamerSharpAudio.cs @@ -302,8 +302,10 @@ namespace Vocaluxe.Lib.Sound if (_Loop) Position = 0; else + { Finished = true; - Close(); + Close(); + } break; case MessageType.Error: GException error; @@ -312,7 +314,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(); From 1e2accffba0cdc5f6f4c51a2469b5c1ceb576f73 Mon Sep 17 00:00:00 2001 From: Flamefire Date: Fri, 14 Mar 2014 15:54:01 +0100 Subject: [PATCH 35/38] Gst#: Return correct volume and use normalized values inside --- Vocaluxe/Lib/Sound/CGstreamerSharpAudio.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Vocaluxe/Lib/Sound/CGstreamerSharpAudio.cs b/Vocaluxe/Lib/Sound/CGstreamerSharpAudio.cs index da0e2ca0..b7795c0a 100644 --- a/Vocaluxe/Lib/Sound/CGstreamerSharpAudio.cs +++ b/Vocaluxe/Lib/Sound/CGstreamerSharpAudio.cs @@ -225,9 +225,9 @@ namespace Vocaluxe.Lib.Sound private readonly Stopwatch _FadeTimer = new Stopwatch(); private float _FadeTime; private float _FadeVolume; - private float _Volume = 100f; + private float _Volume = 1f; - private float _MaxVolume = 100f; + private float _MaxVolume = 1f; private volatile float _Duration = -1f; private volatile float _Position; @@ -384,21 +384,21 @@ namespace Vocaluxe.Lib.Sound 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; } } From 23364c3bcb9c890e317c70885c536d5f3d77b035 Mon Sep 17 00:00:00 2001 From: Flamefire Date: Fri, 14 Mar 2014 16:27:12 +0100 Subject: [PATCH 36/38] Add a class for fading (we don't have to implement this multiple times) --- Vocaluxe/Lib/Sound/CGstreamerSharpAudio.cs | 65 +++++++++++----------- VocaluxeLib/CFading.cs | 64 +++++++++++++++++++++ VocaluxeLib/VocaluxeLib.csproj | 1 + 3 files changed, 98 insertions(+), 32 deletions(-) create mode 100644 VocaluxeLib/CFading.cs diff --git a/Vocaluxe/Lib/Sound/CGstreamerSharpAudio.cs b/Vocaluxe/Lib/Sound/CGstreamerSharpAudio.cs index b7795c0a..2b43716f 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 @@ -213,18 +213,21 @@ namespace Vocaluxe.Lib.Sound private class CGstreamerSharpAudioStream { + private enum EStreamAction + { + Nothing, + Pause, + Stop, + Close + } + private Element _Element; private bool _Loop; 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 CFading _Fading; + private EStreamAction _AfterFadeAction; private float _Volume = 1f; private float _MaxVolume = 1f; @@ -358,28 +361,26 @@ 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 @@ -460,25 +461,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/VocaluxeLib/CFading.cs b/VocaluxeLib/CFading.cs new file mode 100644 index 00000000..5f04e647 --- /dev/null +++ b/VocaluxeLib/CFading.cs @@ -0,0 +1,64 @@ +#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) + { + _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/VocaluxeLib.csproj b/VocaluxeLib/VocaluxeLib.csproj index d44d9b74..22d6a2b1 100644 --- a/VocaluxeLib/VocaluxeLib.csproj +++ b/VocaluxeLib/VocaluxeLib.csproj @@ -130,6 +130,7 @@ + From 790eda4e1574ec1bf9ccbafaa907bc984035b8c4 Mon Sep 17 00:00:00 2001 From: Flamefire Date: Fri, 14 Mar 2014 18:03:37 +0100 Subject: [PATCH 37/38] Use CFading where possible --- Vocaluxe/Base/CBackgroundMusic.cs | 16 ++- Vocaluxe/Base/CCursor.cs | 48 ++------- Vocaluxe/Base/CGraphics.cs | 101 ++++++------------ Vocaluxe/Base/CSettings.cs | 2 +- Vocaluxe/Lib/Sound/CGstreamerSharpAudio.cs | 8 -- Vocaluxe/Lib/Sound/COpenALPlay.cs | 54 ++++------ Vocaluxe/Lib/Sound/CPortAudioPlay.cs | 65 +++++------ Vocaluxe/Lib/Sound/IPlayback.cs | 8 ++ VocaluxeLib/CFading.cs | 2 + .../Menu/SongMenu/CSongMenuFramework.cs | 17 ++- 10 files changed, 119 insertions(+), 202 deletions(-) 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/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/CGraphics.cs b/Vocaluxe/Base/CGraphics.cs index 92a2577b..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) @@ -483,8 +451,7 @@ namespace Vocaluxe.Base if (_CurrentPopupScreen == EPopupScreens.NoPopup && diff != 0) { ShowPopup(EPopupScreens.PopupVolumeControl); - _VolumePopupTimer.Reset(); - _VolumePopupTimer.Start(); + _VolumePopupTimer.Restart(); } CBackgroundMusic.ApplyVolume(); @@ -498,7 +465,7 @@ namespace Vocaluxe.Base CDraw.MakeScreenShot(); else { - if (!_Fading) + if (_Fading == null) { bool handled = false; if (_CurrentPopupScreen != EPopupScreens.NoPopup) @@ -562,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) @@ -594,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/CSettings.cs b/Vocaluxe/Base/CSettings.cs index 8d0c527b..e978691d 100644 --- a/Vocaluxe/Base/CSettings.cs +++ b/Vocaluxe/Base/CSettings.cs @@ -129,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/Lib/Sound/CGstreamerSharpAudio.cs b/Vocaluxe/Lib/Sound/CGstreamerSharpAudio.cs index 2b43716f..dc856e98 100644 --- a/Vocaluxe/Lib/Sound/CGstreamerSharpAudio.cs +++ b/Vocaluxe/Lib/Sound/CGstreamerSharpAudio.cs @@ -213,14 +213,6 @@ namespace Vocaluxe.Lib.Sound private class CGstreamerSharpAudioStream { - private enum EStreamAction - { - Nothing, - Pause, - Stop, - Close - } - private Element _Element; private bool _Loop; public volatile bool Closed = true; diff --git a/Vocaluxe/Lib/Sound/COpenALPlay.cs b/Vocaluxe/Lib/Sound/COpenALPlay.cs index 67891ffb..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(); @@ -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 82af2e91..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; @@ -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)); @@ -927,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/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/VocaluxeLib/CFading.cs b/VocaluxeLib/CFading.cs index 5f04e647..0b6761cb 100644 --- a/VocaluxeLib/CFading.cs +++ b/VocaluxeLib/CFading.cs @@ -34,6 +34,8 @@ namespace VocaluxeLib /// 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; 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); } } } From 37895da9b24b5c77220b3663635545f82435b918 Mon Sep 17 00:00:00 2001 From: Flamefire Date: Fri, 14 Mar 2014 18:21:50 +0100 Subject: [PATCH 38/38] Fix some namings --- ClientServerLib/ClientServerLib/CDiscover.cs | 59 ++++++++++---------- 1 file changed, 28 insertions(+), 31 deletions(-) diff --git a/ClientServerLib/ClientServerLib/CDiscover.cs b/ClientServerLib/ClientServerLib/CDiscover.cs index ecff0173..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)) {Name = "Client discover"}; - _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