diff --git a/Output/CreditsRessourcesDB.sqlite b/Output/CreditsRessourcesDB.sqlite new file mode 100644 index 00000000..dbfe78bb Binary files /dev/null and b/Output/CreditsRessourcesDB.sqlite differ diff --git a/Output/Themes/Ambient/Screens/ScreenOptionsSound.xml b/Output/Themes/Ambient/Screens/ScreenOptionsSound.xml index 5d3d0e9e..259915bd 100644 --- a/Output/Themes/Ambient/Screens/ScreenOptionsSound.xml +++ b/Output/Themes/Ambient/Screens/ScreenOptionsSound.xml @@ -1,7 +1,7 @@  - 1 + 2 Video @@ -394,4 +394,4 @@ 1 - \ No newline at end of file + diff --git a/Output/Themes/Changelog/Changelog_ScreenOptionsSound.txt b/Output/Themes/Changelog/Changelog_ScreenOptionsSound.txt new file mode 100644 index 00000000..5bdf4bfd --- /dev/null +++ b/Output/Themes/Changelog/Changelog_ScreenOptionsSound.txt @@ -0,0 +1,18 @@ +ScreenOptionsSound + +++++++++++ +Version 2: + +Add: + + + + + + + +and some texts for description (Text2, Text3, Text4) +"TR_SCREENOSOUND_BACKGROUNDMUSIC" +"TR_SCREENOSOUND_BACKGROUNDMUSICVOLUME" +"TR_SCREENOSOUND_BACKGROUNDMUSICSOURCE" +++++++++++ diff --git a/Vocaluxe/Base/CConfig.cs b/Vocaluxe/Base/CConfig.cs index 74c13ce6..87d16531 100644 --- a/Vocaluxe/Base/CConfig.cs +++ b/Vocaluxe/Base/CConfig.cs @@ -191,7 +191,7 @@ namespace Vocaluxe.Base public static EPlaybackLib PlayBackLib = EPlaybackLib.PortAudio; public static ERecordLib RecordLib = ERecordLib.PortAudio; public static EBufferSize AudioBufferSize = EBufferSize.b2048; - public static int AudioLatency = 100; + public static int AudioLatency = 125; public static int BackgroundMusicVolume = 50; public static EOffOn BackgroundMusic = EOffOn.TR_CONFIG_ON; public static EBackgroundMusicSource BackgroundMusicSource = EBackgroundMusicSource.TR_CONFIG_NO_OWN_MUSIC; @@ -509,7 +509,7 @@ namespace Vocaluxe.Base writer.WriteElementString("AudioLatency", AudioLatency.ToString()); writer.WriteComment("Background Music"); - writer.WriteElementString("BackgroundMusicEnabled", Enum.GetName(typeof(EOffOn), BackgroundMusic)); + writer.WriteElementString("BackgroundMusic", Enum.GetName(typeof(EOffOn), BackgroundMusic)); writer.WriteComment("Background Music Volume from 0 to 100"); writer.WriteElementString("BackgroundMusicVolume", BackgroundMusicVolume.ToString()); diff --git a/Vocaluxe/Base/CDataBase.cs b/Vocaluxe/Base/CDataBase.cs index 4dec5522..15c6f6f2 100644 --- a/Vocaluxe/Base/CDataBase.cs +++ b/Vocaluxe/Base/CDataBase.cs @@ -27,14 +27,17 @@ namespace Vocaluxe.Base private static string _HighscoreFilePath; private static string _CoverFilePath; + private static string _CreditsRessourcesFilePath; public static void Init() { _HighscoreFilePath = Path.Combine(System.Environment.CurrentDirectory, CSettings.sFileHighscoreDB); _CoverFilePath = Path.Combine(System.Environment.CurrentDirectory, CSettings.sFileCoverDB); + _CreditsRessourcesFilePath = Path.Combine(System.Environment.CurrentDirectory, CSettings.sFileCreditsRessourcesDB); InitHighscoreDB(); InitCoverDB(); + InitCreditsRessourcesDB(); } #region Highscores @@ -126,7 +129,7 @@ namespace Vocaluxe.Base command.Parameters.Add("@Medley", System.Data.DbType.Int32, 0).Value = Medley; command.Parameters.Add("@Duet", System.Data.DbType.Int32, 0).Value = Duet; command.Parameters.Add("@Difficulty", System.Data.DbType.Int32, 0).Value = (int)player.Difficulty; - + SQLiteDataReader reader = null; try { @@ -194,7 +197,7 @@ namespace Vocaluxe.Base SQLiteCommand command; Score = new List(); - + try { connection.Open(); @@ -223,7 +226,7 @@ namespace Vocaluxe.Base command.Parameters.Add("@SongID", System.Data.DbType.Int32, 0).Value = DataBaseSongID; command.Parameters.Add("@Medley", System.Data.DbType.Int32, 0).Value = Medley; command.Parameters.Add("@Duet", System.Data.DbType.Int32, 0).Value = Duet; - + SQLiteDataReader reader = null; try { @@ -248,13 +251,13 @@ namespace Vocaluxe.Base Score.Add(score); } - + reader.Close(); - reader.Dispose(); + reader.Dispose(); } - + } - + command.Dispose(); connection.Close(); @@ -360,7 +363,7 @@ namespace Vocaluxe.Base reader.Close(); reader.Dispose(); } - + return -1; } @@ -679,7 +682,7 @@ namespace Vocaluxe.Base command.Parameters.Add("@id", System.Data.DbType.Int32, 0).Value = data.id; command.ExecuteNonQuery(); } - + //Delete old tables after conversion command.CommandText = "DROP TABLE US_Scores;"; command.ExecuteNonQuery(); @@ -726,7 +729,7 @@ namespace Vocaluxe.Base command.CommandText = "PRAGMA table_info(US_Scores);"; reader = command.ExecuteReader(); - + bool dateExists = false; @@ -743,12 +746,12 @@ namespace Vocaluxe.Base } } } - + reader.Close(); //This is a USDX 1.01 DB - if(!dateExists) + if (!dateExists) command.CommandText = "INSERT INTO Scores (SongID, PlayerName, Score, LineNr, Date, Medley, Duet, Difficulty) SELECT SongID, Player, Score, '0', '0', '0', '0', Difficulty from US_Scores"; else // This is a CMD 1.01 DB command.CommandText = "INSERT INTO Scores (SongID, PlayerName, Score, LineNr, Date, Medley, Duet, Difficulty) SELECT SongID, Player, Score, '0', Date, '0', '0', Difficulty from US_Scores"; @@ -790,9 +793,9 @@ namespace Vocaluxe.Base data.id = Sqlite3.sqlite3_column_int(Stmt, 0); - byte[] bytes = Sqlite3.sqlite3_column_rawbytes(Stmt, 1); + byte[] bytes = Sqlite3.sqlite3_column_rawbytes(Stmt, 1); data.str1 = UTF8.GetString(Encoding.Convert(CP1252, UTF8, bytes)); - + bytes = Sqlite3.sqlite3_column_rawbytes(Stmt, 2); data.str2 = UTF8.GetString(Encoding.Convert(CP1252, UTF8, bytes)); @@ -802,7 +805,7 @@ namespace Vocaluxe.Base } Stmt = new Sqlite3.Vdbe(); - + if (!dateExists) res = Sqlite3.sqlite3_prepare_v2(OldDB, "SELECT rowid, Player FROM US_Scores", -1, ref Stmt, 0); else @@ -830,7 +833,7 @@ namespace Vocaluxe.Base if (dateExists) data.ticks = UnixTimeToTicks(Sqlite3.sqlite3_column_int(Stmt, 2)); - + scores.Add(data); } Sqlite3.sqlite3_finalize(Stmt); @@ -863,14 +866,14 @@ namespace Vocaluxe.Base command.Parameters.Add("@id", System.Data.DbType.Int32, 0).Value = data.id; command.ExecuteNonQuery(); } - + //Delete old tables after conversion command.CommandText = "DROP TABLE US_Scores;"; command.ExecuteNonQuery(); command.CommandText = "DROP TABLE US_Songs;"; command.ExecuteNonQuery(); - + reader.Dispose(); command.Dispose(); connection.Close(); @@ -884,7 +887,7 @@ namespace Vocaluxe.Base #region open db SQLiteConnection connSource = new SQLiteConnection(); connSource.ConnectionString = "Data Source=" + SourceDBPath; - + try { connSource.Open(); @@ -1034,7 +1037,7 @@ namespace Vocaluxe.Base return false; } - + int w = MaxSize; int h = MaxSize; @@ -1051,7 +1054,7 @@ namespace Vocaluxe.Base byte[] data = new byte[w * h * 4]; BitmapData bmp_data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); - Marshal.Copy(bmp_data.Scan0, data, 0, w*h*4); + Marshal.Copy(bmp_data.Scan0, data, 0, w * h * 4); bmp.UnlockBits(bmp_data); bmp.Dispose(); @@ -1197,6 +1200,273 @@ namespace Vocaluxe.Base } #endregion Cover + #region CreditsRessources + public static bool GetCreditsRessource(string FileName, ref STexture tex) + { + bool result = false; + + SQLiteConnection connection = new SQLiteConnection(); + connection.ConnectionString = "Data Source=" + _CreditsRessourcesFilePath; + SQLiteCommand command; + try + { + connection.Open(); + } + catch (Exception) + { + return false; + } + command = new SQLiteCommand(connection); + + command.CommandText = "SELECT id, width, height FROM Images WHERE [Path] = @path"; + command.Parameters.Add("@path", System.Data.DbType.String, 0).Value = FileName; + + SQLiteDataReader reader = null; + try + { + reader = command.ExecuteReader(); + } + catch (Exception) + { + throw; + } + + if (reader != null && reader.HasRows) + { + reader.Read(); + int id = reader.GetInt32(0); + int w = reader.GetInt32(1); + int h = reader.GetInt32(2); + reader.Close(); + + command.CommandText = "SELECT Data FROM ImageData WHERE ImageID = " + id.ToString(); + try + { + reader = command.ExecuteReader(); + } + catch (Exception) + { + throw; + } + + if (reader.HasRows) + { + result = true; + reader.Read(); + byte[] data = GetBytes(reader); + tex = CDraw.AddTexture(w, h, ref data); + } + } + + if (reader != null) + { + reader.Close(); + reader.Dispose(); + } + command.Dispose(); + connection.Close(); + connection.Dispose(); + + return result; + } + + //If you want to add an image to db, call this method! + private static bool AddImageToCreditsDB(String ImagePath) + { + bool result = false; + STexture tex; + + if (File.Exists(ImagePath)) + { + + SQLiteConnection connection = new SQLiteConnection(); + connection.ConnectionString = "Data Source=" + _CreditsRessourcesFilePath; + SQLiteCommand command; + try + { + connection.Open(); + } + catch (Exception) + { + return false; + } + command = new SQLiteCommand(connection); + + SQLiteDataReader reader = null; + + if (reader != null) + reader.Close(); + + Bitmap origin; + try + { + origin = new Bitmap(ImagePath); + } + catch (Exception) + { + CLog.LogError("Error loading Texture: " + ImagePath); + tex = new STexture(-1); + + if (reader != null) + { + reader.Close(); + reader.Dispose(); + } + command.Dispose(); + connection.Close(); + connection.Dispose(); + + return false; + } + + int w = origin.Width; + int h = origin.Height; + + Bitmap bmp = new Bitmap(w, h); + Graphics g = Graphics.FromImage(bmp); + g.DrawImage(origin, new Rectangle(0, 0, w, h)); + g.Dispose(); + tex = CDraw.AddTexture(bmp); + byte[] data = new byte[w * h * 4]; + + BitmapData bmp_data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); + Marshal.Copy(bmp_data.Scan0, data, 0, w * h * 4); + bmp.UnlockBits(bmp_data); + bmp.Dispose(); + + command.CommandText = "INSERT INTO Images (Path, width, height) " + + "VALUES (@path, " + w.ToString() + ", " + h.ToString() + ")"; + command.Parameters.Add("@path", System.Data.DbType.String, 0).Value = Path.GetFileName(ImagePath); + command.ExecuteNonQuery(); + + command.CommandText = "SELECT id FROM Images WHERE [Path] = @path"; + command.Parameters.Add("@path", System.Data.DbType.String, 0).Value = Path.GetFileName(ImagePath); + reader = null; + try + { + reader = command.ExecuteReader(); + } + catch (Exception) + { + throw; + } + + if (reader != null) + { + reader.Read(); + int id = reader.GetInt32(0); + reader.Close(); + command.CommandText = "INSERT INTO ImageData (ImageID, Data) " + + "VALUES ('" + id.ToString() + "', @data)"; + command.Parameters.Add("@data", System.Data.DbType.Binary, 20).Value = data; + command.ExecuteReader(); + result = true; + } + } + + return result; + } + + private static bool InitCreditsRessourcesDB() + { + SQLiteConnection connection = new SQLiteConnection(); + connection.ConnectionString = "Data Source=" + _CreditsRessourcesFilePath; + SQLiteCommand command; + + try + { + connection.Open(); + } + catch (Exception) + { + return false; + } + + command = new SQLiteCommand(connection); + command.CommandText = "SELECT Value FROM Version"; + + SQLiteDataReader reader = null; + + try + { + reader = command.ExecuteReader(); + } + catch (Exception) + { + ; + } + + if (reader == null) + { + // Log error + CLog.LogError("Can't find Credits-DB!"); + } + else if (reader.FieldCount == 0) + { + // Log error + CLog.LogError("Can't find Credits-DB! Field-Count = 0"); + } + else + { + reader.Read(); + + if (reader.GetInt32(0) < CSettings.iDatabaseHighscoreVersion) + { + // update database + } + } + + if (reader != null) + { + reader.Close(); + reader.Dispose(); + } + + command.Dispose(); + + connection.Close(); + connection.Dispose(); + + return true; + } + + private static void CreateCreditsRessourcesDB() + { + SQLiteConnection connection = new SQLiteConnection(); + connection.ConnectionString = "Data Source=" + _CreditsRessourcesFilePath; + SQLiteCommand command; + + try + { + connection.Open(); + } + catch (Exception) + { + return; + } + + command = new SQLiteCommand(connection); + + command.CommandText = "CREATE TABLE IF NOT EXISTS Version ( id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, Value INTEGER NOT NULL);"; + command.ExecuteNonQuery(); + + command.CommandText = "INSERT INTO Version (id, Value) VALUES(NULL, " + CSettings.iDatabaseCreditsRessourcesVersion.ToString() + ")"; + command.ExecuteNonQuery(); + + command.CommandText = "CREATE TABLE IF NOT EXISTS Images ( id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, " + + "Path TEXT NOT NULL, width INTEGER NOT NULL, height INTEGER NOT NULL);"; + command.ExecuteNonQuery(); + + command.CommandText = "CREATE TABLE IF NOT EXISTS ImageData ( id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, " + + "ImageID INTEGER NOT NULL, Data BLOB NOT NULL);"; + command.ExecuteNonQuery(); + + command.Dispose(); + connection.Close(); + connection.Dispose(); + } + #endregion CreditsRessources + private static byte[] GetBytes(SQLiteDataReader reader) { const int CHUNK_SIZE = 2 * 1024; @@ -1223,4 +1493,4 @@ namespace Vocaluxe.Base return t70.Ticks; } } -} +} \ No newline at end of file diff --git a/Vocaluxe/Base/CSettings.cs b/Vocaluxe/Base/CSettings.cs index b7d0ed09..40d2a062 100644 --- a/Vocaluxe/Base/CSettings.cs +++ b/Vocaluxe/Base/CSettings.cs @@ -51,6 +51,7 @@ namespace Vocaluxe.Base public const int iDatabaseHighscoreVersion = 1; public const int iDatabaseCoverVersion = 1; + public const int iDatabaseCreditsRessourcesVersion = 1; public static int iRenderW = 1280; @@ -72,6 +73,7 @@ namespace Vocaluxe.Base public const string sFileOldHighscoreDB = "Ultrastar.db"; public static string sFileHighscoreDB = "HighscoreDB.sqlite"; public const string sFileCoverDB = "CoverDB.sqlite"; + public const string sFileCreditsRessourcesDB = "CreditsRessourcesDB.sqlite"; public const string sFilePerformanceLog = "Performance.log"; public const string sFileErrorLog = "Error.log"; public const string sFileBenchmarkLog = "Benchmark.log"; diff --git a/Vocaluxe/Lib/Sound/CPortAudioPlay.cs b/Vocaluxe/Lib/Sound/CPortAudioPlay.cs index 43623c5c..dc23bc91 100644 --- a/Vocaluxe/Lib/Sound/CPortAudioPlay.cs +++ b/Vocaluxe/Lib/Sound/CPortAudioPlay.cs @@ -677,6 +677,21 @@ namespace Vocaluxe.Lib.Sound { if (EventDecode.WaitOne(10)) { + lock (MutexSyncSignals) + { + if (_SetSkip) + { + _skip = true; + EventDecode.Set(); + _waiting = true; + } + + _SetSkip = false; + + _Start = _SetStart; + _Loop = _SetLoop; + } + if (_skip) { DoSkip(); @@ -689,25 +704,6 @@ namespace Vocaluxe.Lib.Sound Update(); } } - - if (!_terminated) - { - lock (MutexSyncSignals) - { - if (_SetSkip) - { - _skip = true; - EventDecode.Set(); - _waiting = true; - } - - _SetSkip = false; - - _Start = _SetStart; - _Loop = _SetLoop; - } - } - } DoFree(); diff --git a/Vocaluxe/Lib/Sound/CPortAudioRecord.cs b/Vocaluxe/Lib/Sound/CPortAudioRecord.cs index 04096ab9..87bff1ab 100644 --- a/Vocaluxe/Lib/Sound/CPortAudioRecord.cs +++ b/Vocaluxe/Lib/Sound/CPortAudioRecord.cs @@ -245,6 +245,9 @@ namespace Vocaluxe.Lib.Sound if (!_initialized) return null; + if (_Devices.Count == 0) + return null; + return _Devices.ToArray(); } diff --git a/Vocaluxe/Lib/Video/CVideoDecoderFFmpeg.cs b/Vocaluxe/Lib/Video/CVideoDecoderFFmpeg.cs index 6b566e39..b8c38f49 100644 --- a/Vocaluxe/Lib/Video/CVideoDecoderFFmpeg.cs +++ b/Vocaluxe/Lib/Video/CVideoDecoderFFmpeg.cs @@ -214,33 +214,34 @@ namespace Vocaluxe.Lib.Video class Decoder { - private IntPtr _instance = IntPtr.Zero; - private IntPtr _videodecoder = IntPtr.Zero; - private IntPtr _package = IntPtr.Zero; - private Stopwatch _Timer = new Stopwatch(); - private CLOSEPROC _Closeproc; - private int _StreamID; - private string _FileName; + private IntPtr _instance = IntPtr.Zero; // acinerella instance + private IntPtr _videodecoder = IntPtr.Zero; // acinerella video decoder instance + + private Stopwatch _LoopTimer = new Stopwatch(); + private CLOSEPROC _Closeproc; // delegate for stream closing + private int _StreamID; // stream ID for stream closing + private string _FileName; // current video file name - private FileStream _fs; - private TAc_read_callback _rc; - private TAc_seek_callback _sc; + private FileStream _fs; // video file stream + private TAc_read_callback _rc; // read callback for acinerella + private TAc_seek_callback _sc; // seek callback for acinerella private bool _FileOpened = false; - private float _VideoTimeBase = 0f; - private float _VideoTime = 0f; - private float _ActualVideoTime = 0f; - private bool _waiting = false; - private bool _skip = false; + private float _VideoTimeBase = 0f; // frame time + private float _VideoDecoderTime = 0f; // time of last decoded frame + private float _CurrentVideoTime = 0f; // current video position + private bool _BufferFull = false; // buffer is full, waiting for free frame slot + + private bool _skip = false; // do skip private float _Time = 0f; private float _Gap = 0f; private float _Start = 0f; private bool _Loop = false; private float _Duration = 0f; - private float _VideoSkipTime = 0f; - private float _NegativeSkipTime = 0f; - private float _SkipTime = 0f; + private float _VideoSkipTime = 0f; // = VideoGap + private float _SkipTime = 0f; // = Start + VideoGap + private bool _Paused = false; private bool _NoMoreFrames = false; private bool _Finished = false; @@ -292,15 +293,16 @@ namespace Vocaluxe.Lib.Video get { return _Paused; } set { - _Paused = value; lock (MutexSyncSignals) { + _Paused = value; if (_Paused) - _Timer.Stop(); + { + _LoopTimer.Stop(); + } else { - _Timer.Start(); - EventDecode.Set(); + _LoopTimer.Start(); } } } @@ -329,7 +331,7 @@ namespace Vocaluxe.Lib.Video return false; _FileName = FileName; - _thread.Priority = ThreadPriority.Highest; + _thread.Priority = ThreadPriority.Normal; _thread.Name = Path.GetFileName(FileName); _thread.Start(); return true; @@ -347,12 +349,12 @@ namespace Vocaluxe.Lib.Video { lock (MutexSyncSignals) { - _SetTime += _Timer.ElapsedMilliseconds / 1000f; + _SetTime += _LoopTimer.ElapsedMilliseconds / 1000f; VideoTime = _SetTime; - _Timer.Stop(); - _Timer.Reset(); - _Timer.Start(); + _LoopTimer.Stop(); + _LoopTimer.Reset(); + _LoopTimer.Start(); } @@ -361,12 +363,12 @@ namespace Vocaluxe.Lib.Video return true; } - if (_Time - _SetTime >= 0 || _SetTime > Time) + if (_SetTime != Time) { lock (MutexSyncSignals) { _SetTime = Time; - VideoTime = _VideoTime; + VideoTime = _CurrentVideoTime; } UploadNewFrame(ref frame); EventDecode.Set(); @@ -393,17 +395,15 @@ namespace Vocaluxe.Lib.Video #region Threading private void DoSkip() { - lock (MutexSyncSignals) - { - _VideoSkipTime = _Gap; - _NegativeSkipTime = _Start + _Gap; - _SkipTime = _Start + _Gap; - _BeforeLoop = false; - } + string extension = Path.GetExtension(_FileName); //just a workaround for the mkv-search-bug in ffmpeg - if (_SkipTime > 0) + _VideoSkipTime = _Gap; + _SkipTime = _Start + _Gap; + _BeforeLoop = false; + + if (_SkipTime > 0 && extension != ".mkv") { - _VideoTime = _SkipTime; + _VideoDecoderTime = _SkipTime; try { CAcinerella.ac_seek(_videodecoder, -1, (Int64)(_SkipTime * 1000f)); @@ -416,10 +416,11 @@ namespace Vocaluxe.Lib.Video } else { - _VideoTime = 0f; + _VideoDecoderTime = 0f; try { - CAcinerella.ac_seek(_videodecoder, -1, (Int64)0); + if (extension != ".mkv") + CAcinerella.ac_seek(_videodecoder, -1, (Int64)0); } catch (Exception e) { @@ -427,7 +428,10 @@ namespace Vocaluxe.Lib.Video } } - _ActualVideoTime = _VideoTime; + lock (MutexSyncSignals) + { + _CurrentVideoTime = _VideoDecoderTime; + } lock (MutexFramebuffer) { @@ -438,46 +442,41 @@ namespace Vocaluxe.Lib.Video } } - _waiting = false; + _BufferFull = false; + _skip = false; + EventDecode.Set(); } private void Execute() { DoOpen(); - + EventDecode.Set(); + while (!_terminated) { - if (EventDecode.WaitOne(1) || !_waiting) - { - if (_skip) - { - DoSkip(); - _skip = false; - } - - if (!_waiting) - { - DoDecode(); - } - - if (_waiting) - Copy(); - } - if (!_terminated) + if (EventDecode.WaitOne(10)) { lock (MutexSyncSignals) { _Time = _SetTime; if (_SetSkip) _skip = true; - + _SetSkip = false; _Gap = _SetGap; _Start = _SetStart; _Loop = _SetLoop; } + + if (_skip) + DoSkip(); + + if (!_BufferFull) + DoDecode(); + + if (_BufferFull) + Copy(); } - } DoFree(); @@ -543,7 +542,7 @@ namespace Vocaluxe.Lib.Video if (Videodecoder.stream_info.video_info.frames_per_second > 0) _VideoTimeBase = 1f / (float)Videodecoder.stream_info.video_info.frames_per_second; - _VideoTime = 0f; + _VideoDecoderTime = 0f; _Time = 0f; for (int i = 0; i < _FrameBuffer.Length; i++) @@ -562,14 +561,14 @@ namespace Vocaluxe.Lib.Video if (!_FileOpened) return; - if (_Paused || _NoMoreFrames) + if (_Paused || _NoMoreFrames || _BufferFull) return; - if ((_NegativeSkipTime < 0f) && (_Time + _NegativeSkipTime >= 0f)) - _NegativeSkipTime = 0f; + if ((_SkipTime < 0f) && (_Time + _SkipTime >= 0f)) + _SkipTime = 0f; float myTime = _Time + _VideoSkipTime; - float TimeDifference = myTime - _VideoTime; + float TimeDifference = myTime - _VideoDecoderTime; bool DropFrame = false; if (TimeDifference >= (FRAMEDROPCOUNT - 1) * _VideoTimeBase) @@ -632,7 +631,6 @@ namespace Vocaluxe.Lib.Video lock (MutexSyncSignals) { - _ActualVideoTime = 0f; _Start = 0f; _Gap = 0f; _SetTime = 0f; @@ -653,6 +651,7 @@ namespace Vocaluxe.Lib.Video private void Copy() { int num = -1; + lock (MutexFramebuffer) { for (int i = 0; i < _FrameBuffer.Length; i++) @@ -665,24 +664,38 @@ namespace Vocaluxe.Lib.Video } if (num == -1) - _waiting = true; + { + _BufferFull = true; + EventDecode.Reset(); + } else { TAc_decoder Videodecoder = (TAc_decoder)Marshal.PtrToStructure(_videodecoder, typeof(TAc_decoder)); - _VideoTime = (float)Videodecoder.timecode; - _FrameBuffer[num].time = _VideoTime; + _VideoDecoderTime = (float)Videodecoder.timecode; + _FrameBuffer[num].time = _VideoDecoderTime; if (Videodecoder.buffer != IntPtr.Zero) { Marshal.Copy(Videodecoder.buffer, _FrameBuffer[num].data, 0, _Width * _Height * 4); - + _FrameBuffer[num].displayed = false; } - - _waiting = false; + + int numfull = 0; + for (int i = 0; i < _FrameBuffer.Length; i++) + { + if (!_FrameBuffer[i].displayed) + numfull++; + } + + if (numfull < _FrameBuffer.Length) + _BufferFull = false; } } + + if (!_BufferFull) + EventDecode.Set(); } private void UploadNewFrame(ref STexture frame) @@ -705,8 +718,13 @@ namespace Vocaluxe.Lib.Video { CDraw.UpdateTexture(ref frame, ref _FrameBuffer[num].data); } - _ActualVideoTime = _FrameBuffer[num].time; + + lock (MutexSyncSignals) + { + _CurrentVideoTime = _FrameBuffer[num].time; + } _Finished = false; + EventDecode.Set(); } else { @@ -714,7 +732,6 @@ namespace Vocaluxe.Lib.Video _Finished = true; } } - EventDecode.Set(); } private int FindFrame() @@ -726,27 +743,28 @@ namespace Vocaluxe.Lib.Video { float td = _SetTime + _VideoSkipTime - _FrameBuffer[i].time; + if (td > _VideoTimeBase * 2 || td < -1f * _VideoTimeBase * (_FrameBuffer.Length + 1)) + { + _FrameBuffer[i].displayed = true; + } + if (!_FrameBuffer[i].displayed && (td < diff) && (td > _VideoTimeBase)) { diff = Math.Abs(_FrameBuffer[i].time - _SetTime - _VideoSkipTime); Result = i; } - - if (td > _VideoTimeBase * 2) - _FrameBuffer[i].displayed = true; } if (Result != -1) + { _FrameBuffer[Result].displayed = true; + } return Result; } private void DoFree() { - if (_package != IntPtr.Zero) - CAcinerella.ac_free_package(_package); - if (_videodecoder != IntPtr.Zero) CAcinerella.ac_free_decoder(_videodecoder); diff --git a/Vocaluxe/Menu/CGraphics.cs b/Vocaluxe/Menu/CGraphics.cs index f96e5add..a47dd769 100644 --- a/Vocaluxe/Menu/CGraphics.cs +++ b/Vocaluxe/Menu/CGraphics.cs @@ -31,6 +31,8 @@ namespace Vocaluxe.Menu ScreenNames = 14, + ScreenCredits = 15, + ScreenNull = -1 } @@ -219,6 +221,7 @@ namespace Vocaluxe.Menu ScreenList.Add(new CScreenOptionsVideo()); ScreenList.Add(new CScreenOptionsTheme()); ScreenList.Add(new CScreenNames()); + ScreenList.Add(new CScreenCredits()); CLog.StopBenchmark(1, "Build Screen List"); Screens = ScreenList.ToArray(); @@ -246,9 +249,12 @@ namespace Vocaluxe.Menu for (int i = 0; i < Screens.Length; i++) { - CLog.StartBenchmark(1, "Load Theme " + Enum.GetNames(typeof(EScreens))[i]); - Screens[i].LoadTheme(); - CLog.StopBenchmark(1, "Load Theme " + Enum.GetNames(typeof(EScreens))[i]); + if (Enum.GetNames(typeof(EScreens))[i] != Enum.GetName(typeof(EScreens), (int)EScreens.ScreenCredits)) + { + CLog.StartBenchmark(1, "Load Theme " + Enum.GetNames(typeof(EScreens))[i]); + Screens[i].LoadTheme(); + CLog.StopBenchmark(1, "Load Theme " + Enum.GetNames(typeof(EScreens))[i]); + } } } @@ -257,7 +263,10 @@ namespace Vocaluxe.Menu ReloadCursor(); for (int i = 0; i < Screens.Length; i++) { - Screens[i].ReloadTheme(); + if (Enum.GetNames(typeof(EScreens))[i] != Enum.GetName(typeof(EScreens), (int)EScreens.ScreenCredits)) + { + Screens[i].ReloadTheme(); + } } } @@ -266,7 +275,10 @@ namespace Vocaluxe.Menu ReloadCursor(); for (int i = 0; i < Screens.Length; i++) { - Screens[i].ReloadTextures(); + if (Enum.GetNames(typeof(EScreens))[i] != Enum.GetName(typeof(EScreens), (int)EScreens.ScreenCredits)) + { + Screens[i].ReloadTextures(); + } } } @@ -275,7 +287,10 @@ namespace Vocaluxe.Menu CTheme.SaveTheme(); for (int i = 0; i < Screens.Length; i++) { - Screens[i].SaveTheme(); + if (Enum.GetNames(typeof(EScreens))[i] != Enum.GetName(typeof(EScreens), (int)EScreens.ScreenCredits)) + { + Screens[i].SaveTheme(); + } } } diff --git a/Vocaluxe/Screens/CScreenCredits.cs b/Vocaluxe/Screens/CScreenCredits.cs new file mode 100644 index 00000000..278b4720 --- /dev/null +++ b/Vocaluxe/Screens/CScreenCredits.cs @@ -0,0 +1,367 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; +using System.Windows.Forms; + +using Vocaluxe.Base; +using Vocaluxe.Lib.Draw; +using Vocaluxe.Menu; + +enum EDirection +{ + Left, + Right, + Up +} + +class CCreditName +{ + public CStatic image; + public CParticleEffect particle; + public SRectF particleRect; + public EDirection direction; + public float StartTimeUp; + public bool active; +} + +namespace Vocaluxe.Screens +{ + class CScreenCredits :CMenu + { + // Version number for theme files. Increment it, if you've changed something on the theme files! + const int ScreenVersion = 1; + + + private CStatic logo; + private CParticleEffect starsRed; + private CParticleEffect starsBlue; + private List _CreditNames; + + private Stopwatch LogoTimer; + private Stopwatch CreditsTimer; + + public CScreenCredits() + { + Init(); + } + + protected override void Init() + { + base.Init(); + + _ThemeName = "ScreenCredits"; + _ScreenVersion = ScreenVersion; + + LogoTimer = new Stopwatch(); + CreditsTimer = new Stopwatch(); + } + + public override bool HandleInput(KeyEvent KeyEvent) + { + if (KeyEvent.KeyPressed && !Char.IsControl(KeyEvent.Unicode)) + { + + } + else + { + switch (KeyEvent.Key) + { + case Keys.Escape: + case Keys.Back: + CGraphics.FadeTo(EScreens.ScreenMain); + break; + + case Keys.Enter: + CGraphics.FadeTo(EScreens.ScreenMain); + break; + } + } + + return true; + } + + public override bool HandleMouse(MouseEvent MouseEvent) + { + if (MouseEvent.LB && IsMouseOver(MouseEvent)) + { + + } + + if (MouseEvent.LB) + { + CGraphics.FadeTo(EScreens.ScreenMain); + } + + if (MouseEvent.RB) + { + CGraphics.FadeTo(EScreens.ScreenMain); + } + return true; + } + + public override bool UpdateGame() + { + if (!animation()) + { + CGraphics.FadeTo(EScreens.ScreenMain); + } + return true; + } + + public override void OnShow() + { + STexture tex = new STexture(); + STexture particleTex = new STexture(); + + //Vocaluxe-Logo + CDataBase.GetCreditsRessource("Logo_voc.png", ref tex); + logo = new CStatic(tex, new SColorF(1, 1, 1, 1), new SRectF((CSettings.iRenderW - tex.width)/2, -270 , tex.width, tex.height, -2)); + + //Little stars for logo + CDataBase.GetCreditsRessource("PerfectNoteStar.png", ref particleTex); + int numstars = (int)(logo.Rect.W * 0.25f /2f); + starsRed = new CParticleEffect(numstars, new SColorF(1, 0, 0, 1), new SRectF(logo.Rect.X, logo.Rect.Y, logo.Rect.W, logo.Rect.H, -1), particleTex, 35, EParticeType.Star); + starsBlue = new CParticleEffect(numstars, new SColorF(0.149f, 0.415f, 0.819f, 1), new SRectF(logo.Rect.X, logo.Rect.Y, logo.Rect.W, logo.Rect.H, -1), particleTex, 35, EParticeType.Star); + + //Credit names + _CreditNames = new List(); + + CCreditName CreditEntry = new CCreditName(); + + //brunzel + CDataBase.GetCreditsRessource("brunzel.png", ref tex); + CCreditName CreditEntryBrunzel = new CCreditName(); + CreditEntryBrunzel.image = new CStatic(tex, new SColorF(1,1,1,1), new SRectF(-450, 580, 400, 120, -4)); + CreditEntryBrunzel.particleRect = new SRectF(CreditEntryBrunzel.image.Rect.X + 342, CreditEntryBrunzel.image.Rect.Y + 4, 30, 30, -5); + CreditEntryBrunzel.particle = new CParticleEffect(8, new SColorF(1, 0, 0, 1), CreditEntryBrunzel.particleRect, particleTex, 35, EParticeType.Star); + CreditEntryBrunzel.active = true; + CreditEntryBrunzel.direction = EDirection.Left; + _CreditNames.Add(CreditEntryBrunzel); + + //Darkice + CDataBase.GetCreditsRessource("Darkice.png", ref tex); + CCreditName CreditEntryDarkice = new CCreditName(); + CreditEntryDarkice.image = new CStatic(tex, new SColorF(1, 1, 1, 1), new SRectF(CSettings.iRenderW, 580, 400, 120, -4)); + CreditEntryDarkice.particleRect = new SRectF(CreditEntryDarkice.image.Rect.X + 242, CreditEntryDarkice.image.Rect.Y + 23, 30, 30, -5); + CreditEntryDarkice.particle = new CParticleEffect(8, new SColorF(0.149f, 0.415f ,0.819f, 1), CreditEntryDarkice.particleRect, particleTex, 35, EParticeType.Star); + CreditEntryDarkice.active = true; + CreditEntryDarkice.direction = EDirection.Right; + _CreditNames.Add(CreditEntryDarkice); + + //flokuep + CDataBase.GetCreditsRessource("flokuep.png", ref tex); + CCreditName CreditEntryFlokuep = new CCreditName(); + CreditEntryFlokuep.image = new CStatic(tex, new SColorF(1, 1, 1, 1), new SRectF(-450, 580, 400, 120, -4)); + CreditEntryFlokuep.particleRect = new SRectF(CreditEntryFlokuep.image.Rect.X + 141, CreditEntryFlokuep.image.Rect.Y-2, 30, 30, -5); + CreditEntryFlokuep.particle = new CParticleEffect(8, new SColorF(1, 0, 0, 1), CreditEntryFlokuep.particleRect, particleTex, 35, EParticeType.Star); + CreditEntryFlokuep.active = true; + CreditEntryFlokuep.direction = EDirection.Left; + _CreditNames.Add(CreditEntryFlokuep); + + //bohning + CDataBase.GetCreditsRessource("bohning.png", ref tex); + CCreditName CreditEntryBohning = new CCreditName(); + CreditEntryBohning.image = new CStatic(tex, new SColorF(1, 1, 1, 1), new SRectF(CSettings.iRenderW, 580, 350, 110, -4)); + CreditEntryBohning.particleRect = new SRectF(CreditEntryBohning.image.Rect.X + 172, CreditEntryBohning.image.Rect.Y + 16, 10, 10, -5); + CreditEntryBohning.particle = new CParticleEffect(4, new SColorF(0.149f, 0.415f ,0.819f, 1), CreditEntryBohning.particleRect, particleTex, 25, EParticeType.Star); + CreditEntryBohning.active = true; + CreditEntryBohning.direction = EDirection.Right; + _CreditNames.Add(CreditEntryBohning); + + //mesand + CDataBase.GetCreditsRessource("mesand.png", ref tex); + CCreditName CreditEntryMesand = new CCreditName(); + CreditEntryMesand.image = new CStatic(tex, new SColorF(1, 1, 1, 1), new SRectF(-450, 580, 350, 110, -4)); + CreditEntryMesand.particleRect = new SRectF(CreditEntryMesand.image.Rect.X + 240, CreditEntryMesand.image.Rect.Y - 2, 10, 10, -5); + CreditEntryMesand.particle = new CParticleEffect(4, new SColorF(1, 0, 0, 1), CreditEntryMesand.particleRect, particleTex, 25, EParticeType.Star); + CreditEntryMesand.active = true; + CreditEntryMesand.direction = EDirection.Left; + _CreditNames.Add(CreditEntryMesand); + + //babene03 + CDataBase.GetCreditsRessource("babene03.png", ref tex); + CCreditName CreditEntryBabene03 = new CCreditName(); + CreditEntryBabene03.image = new CStatic(tex, new SColorF(1, 1, 1, 1), new SRectF(CSettings.iRenderW, 580, 350, 110, -4)); + CreditEntryBabene03.particleRect = new SRectF(CreditEntryBabene03.image.Rect.X + 7, CreditEntryBabene03.image.Rect.Y + 4, 10, 10, -5); + CreditEntryBabene03.particle = new CParticleEffect(4, new SColorF(0.149f, 0.415f ,0.819f, 1), CreditEntryBabene03.particleRect, particleTex, 25, EParticeType.Star); + CreditEntryBabene03.active = true; + CreditEntryBabene03.direction = EDirection.Right; + _CreditNames.Add(CreditEntryBabene03); + + //pantero + CDataBase.GetCreditsRessource("pantero.png", ref tex); + CCreditName CreditEntrypantero = new CCreditName(); + CreditEntrypantero.image = new CStatic(tex, new SColorF(1, 1, 1, 1), new SRectF(-450, 580, 350, 110, -4)); + CreditEntrypantero.particleRect = new SRectF(CreditEntrypantero.image.Rect.X + 140, CreditEntrypantero.image.Rect.Y + 15, 10, 10, -5); + CreditEntrypantero.particle = new CParticleEffect(4, new SColorF(1, 0, 0, 1), CreditEntrypantero.particleRect, particleTex, 25, EParticeType.Star); + CreditEntrypantero.active = true; + CreditEntrypantero.direction = EDirection.Left; + _CreditNames.Add(CreditEntrypantero); + + //Pinky007 + CDataBase.GetCreditsRessource("Pinky007.png", ref tex); + CCreditName CreditEntryPinky007 = new CCreditName(); + CreditEntryPinky007.image = new CStatic(tex, new SColorF(1, 1, 1, 1), new SRectF(CSettings.iRenderW, 580, 350, 110, -4)); + CreditEntryPinky007.particleRect = new SRectF(CreditEntryPinky007.image.Rect.X + 42, CreditEntryPinky007.image.Rect.Y + 15, 10, 10, -5); + CreditEntryPinky007.particle = new CParticleEffect(4, new SColorF(0.149f, 0.415f ,0.819f, 1), CreditEntryPinky007.particleRect, particleTex, 25, EParticeType.Star); + CreditEntryPinky007.active = true; + CreditEntryPinky007.direction = EDirection.Right; + _CreditNames.Add(CreditEntryPinky007); + + + //CreditEntry.image = new CStatic(tex, new SColorF(1, 1, 1, 1), new SRectF(0, 0, 350, 110, -4)); + + } + + public override void OnShowFinish() + { + base.OnShowFinish(); + + LogoTimer.Start(); + } + + public override bool Draw() + { + base.Draw(); + + //Draw background + CDraw.DrawColor(new SColorF(0, 0.18f, 0.474f, 1), new SRectF(0, 0, CSettings.iRenderW, CSettings.iRenderH, 0)); + + //Draw stars + starsBlue.Update(); + starsBlue.Draw(); + starsRed.Update(); + starsRed.Draw(); + + logo.Draw(); + + //Draw credit-entries + for (int i = 0; i < _CreditNames.Count; i++) + { + if (_CreditNames[i].active) + { + _CreditNames[i].image.Draw(); + _CreditNames[i].particle.Update(); + _CreditNames[i].particle.Draw(); + } + } + return true; + } + + private bool animation() + { + bool active = false; + if (LogoTimer.IsRunning) + { + active = true; + + logo.Rect.Y = -270 + (270f / 3000f) * LogoTimer.ElapsedMilliseconds; + SRectF rect = new SRectF(logo.Rect.X, logo.Rect.Y, logo.Rect.W, logo.Rect.H, -1); + starsRed.Area = rect; + starsBlue.Area = rect; + if (LogoTimer.ElapsedMilliseconds >= 2000 && !CreditsTimer.IsRunning) + { + CreditsTimer.Start(); + } + if (LogoTimer.ElapsedMilliseconds >= 3000) + { + LogoTimer.Stop(); + LogoTimer.Reset(); + } + } + + if (CreditsTimer.IsRunning) + { + active = true; + + for (int i = 0; i < _CreditNames.Count; i++) + { + if (_CreditNames[i].active) + { + switch (_CreditNames[i].direction) + { + case EDirection.Left: + if (i * 4000f <= CreditsTimer.ElapsedMilliseconds) + { + float xOld = _CreditNames[i].image.Rect.X; + _CreditNames[i].image.Rect.X = -450 + (((CSettings.iRenderW - _CreditNames[i].image.Rect.W) / 2)/3000f) * (CreditsTimer.ElapsedMilliseconds-(i*4000f)); + _CreditNames[i].particleRect.X += (_CreditNames[i].image.Rect.X - xOld); + _CreditNames[i].particle.Area = _CreditNames[i].particleRect; + + //Check if name is in middle of screen and should go up + if (_CreditNames[i].image.Rect.X >= (CSettings.iRenderW - _CreditNames[i].image.Rect.W) / 2) + { + _CreditNames[i].direction = EDirection.Up; + _CreditNames[i].StartTimeUp = CreditsTimer.ElapsedMilliseconds; + } + + } + break; + + case EDirection.Right: + if (i * 4000f <= CreditsTimer.ElapsedMilliseconds) + { + float xOld = _CreditNames[i].image.Rect.X; + _CreditNames[i].image.Rect.X = CSettings.iRenderW - (((CSettings.iRenderW - _CreditNames[i].image.Rect.W) / 2) / 3000f) * (CreditsTimer.ElapsedMilliseconds - (i * 4000f)); + _CreditNames[i].particleRect.X -= (xOld - _CreditNames[i].image.Rect.X); + _CreditNames[i].particle.Area = _CreditNames[i].particleRect; + + //Check if name is in middle of screen and should go up + if (_CreditNames[i].image.Rect.X <= (CSettings.iRenderW - _CreditNames[i].image.Rect.W) / 2 ) + { + _CreditNames[i].direction = EDirection.Up; + _CreditNames[i].StartTimeUp = CreditsTimer.ElapsedMilliseconds; + } + + } + break; + + case EDirection.Up: + float yOld = _CreditNames[i].image.Rect.Y; + _CreditNames[i].image.Rect.Y = 580 - (430f / 3000f) * (CreditsTimer.ElapsedMilliseconds - _CreditNames[i].StartTimeUp); + _CreditNames[i].particleRect.Y -= (yOld - _CreditNames[i].image.Rect.Y); + _CreditNames[i].particle.Area = _CreditNames[i].particleRect; + + //Fade names out + if (_CreditNames[i].image.Rect.Y <= 350f) + { + //Catch some bad alpha-values + float alpha = ((250 - _CreditNames[i].image.Rect.Y) / 20); + if(alpha > 1) + { + alpha = 1; + } + else if(alpha < 0) + { + alpha = 0; + } + _CreditNames[i].image.Alpha = 1 - alpha; + } + + //Set name inactive + if (_CreditNames[i].image.Rect.Y <= 150f) + { + _CreditNames[i].active = false; + //Check, if last name is set to false + if (i == _CreditNames.Count - 1) + { + //Will later fade to Main-Screen + active = false; + + //Stop and reset timer for next time + CreditsTimer.Stop(); + CreditsTimer.Reset(); + } + } + break; + } + } + } + } + + return active; + } + } +} diff --git a/Vocaluxe/Screens/CScreenMain.cs b/Vocaluxe/Screens/CScreenMain.cs index 11ed8670..14c0840c 100644 --- a/Vocaluxe/Screens/CScreenMain.cs +++ b/Vocaluxe/Screens/CScreenMain.cs @@ -69,6 +69,10 @@ namespace Vocaluxe.Screens CGraphics.FadeTo(EScreens.ScreenTest); break; + case Keys.C: + CGraphics.FadeTo(EScreens.ScreenCredits); + break; + case Keys.Enter: if (Buttons[htButtons(ButtonSing)].Selected) CGraphics.FadeTo(EScreens.ScreenSong); diff --git a/Vocaluxe/Screens/CScreenOptionsSound.cs b/Vocaluxe/Screens/CScreenOptionsSound.cs index a3fd049e..2e8207f7 100644 --- a/Vocaluxe/Screens/CScreenOptionsSound.cs +++ b/Vocaluxe/Screens/CScreenOptionsSound.cs @@ -12,7 +12,7 @@ namespace Vocaluxe.Screens class CScreenOptionsSound : CMenu { // Version number for theme files. Increment it, if you've changed something on the theme files! - const int ScreenVersion = 1; + const int ScreenVersion = 2; private const string SelectSlideBackgroundMusic = "SelectSlideBackgroundMusic"; private const string SelectSlideBackgroundMusicVolume = "SelectSlideBackgroundMusicVolume"; diff --git a/Vocaluxe/Vocaluxe.csproj b/Vocaluxe/Vocaluxe.csproj index 95aaf2b6..0c3b8104 100644 --- a/Vocaluxe/Vocaluxe.csproj +++ b/Vocaluxe/Vocaluxe.csproj @@ -187,6 +187,7 @@ Form +