diff --git a/Output/Languages/Deutsch.xml b/Output/Languages/Deutsch.xml index a1a1a3fe..ecb1c632 100644 --- a/Output/Languages/Deutsch.xml +++ b/Output/Languages/Deutsch.xml @@ -191,5 +191,6 @@ Video-Hintergründe Video-Vorschau Videos während des Singens + Videos der Hintergrundmusik diff --git a/Output/Languages/English.xml b/Output/Languages/English.xml index d77f8593..e40c62d2 100644 --- a/Output/Languages/English.xml +++ b/Output/Languages/English.xml @@ -191,5 +191,6 @@ Video Backgrounds Video Preview Videos while singing + Display current backgroundmusic video diff --git a/Output/Languages/French.xml b/Output/Languages/French.xml index fd2c6fac..ab0ea416 100644 --- a/Output/Languages/French.xml +++ b/Output/Languages/French.xml @@ -186,5 +186,6 @@ Vidéo en arrière plan Prévisualisation des Vidéos Vidéos pendant que l'on chante + TODO: Display current backgroundmusic video diff --git a/Output/Languages/Spanish.xml b/Output/Languages/Spanish.xml index 6e06dc0b..483e30a3 100644 --- a/Output/Languages/Spanish.xml +++ b/Output/Languages/Spanish.xml @@ -186,5 +186,6 @@ Videos de Fondo Previsualización del Video Videos al Cantar + TODO: Display current backgroundmusic video diff --git a/Output/Themes/Ambient/NextIcon.png b/Output/Themes/Ambient/NextIcon.png new file mode 100644 index 00000000..fb6bf6c4 Binary files /dev/null and b/Output/Themes/Ambient/NextIcon.png differ diff --git a/Output/Themes/Ambient/PauseIcon.png b/Output/Themes/Ambient/PauseIcon.png new file mode 100644 index 00000000..6f9c8870 Binary files /dev/null and b/Output/Themes/Ambient/PauseIcon.png differ diff --git a/Output/Themes/Ambient/PlayIcon.png b/Output/Themes/Ambient/PlayIcon.png new file mode 100644 index 00000000..5f34140b Binary files /dev/null and b/Output/Themes/Ambient/PlayIcon.png differ diff --git a/Output/Themes/Ambient/PreviousIcon.png b/Output/Themes/Ambient/PreviousIcon.png new file mode 100644 index 00000000..9a92bf23 Binary files /dev/null and b/Output/Themes/Ambient/PreviousIcon.png differ diff --git a/Output/Themes/Ambient/RepeatIcon.png b/Output/Themes/Ambient/RepeatIcon.png new file mode 100644 index 00000000..6675a41a Binary files /dev/null and b/Output/Themes/Ambient/RepeatIcon.png differ diff --git a/Output/Themes/Ambient/Resources/NextIcon.psd b/Output/Themes/Ambient/Resources/NextIcon.psd new file mode 100644 index 00000000..a6af8829 Binary files /dev/null and b/Output/Themes/Ambient/Resources/NextIcon.psd differ diff --git a/Output/Themes/Ambient/Resources/PauseIcon.psd b/Output/Themes/Ambient/Resources/PauseIcon.psd new file mode 100644 index 00000000..2046e471 Binary files /dev/null and b/Output/Themes/Ambient/Resources/PauseIcon.psd differ diff --git a/Output/Themes/Ambient/Resources/PlayIcon.psd b/Output/Themes/Ambient/Resources/PlayIcon.psd new file mode 100644 index 00000000..ba63fc5c Binary files /dev/null and b/Output/Themes/Ambient/Resources/PlayIcon.psd differ diff --git a/Output/Themes/Ambient/Resources/PreviousIcon.psd b/Output/Themes/Ambient/Resources/PreviousIcon.psd new file mode 100644 index 00000000..0e5756eb Binary files /dev/null and b/Output/Themes/Ambient/Resources/PreviousIcon.psd differ diff --git a/Output/Themes/Ambient/Resources/RepeatIcon.psd b/Output/Themes/Ambient/Resources/RepeatIcon.psd new file mode 100644 index 00000000..cd1a0637 Binary files /dev/null and b/Output/Themes/Ambient/Resources/RepeatIcon.psd differ diff --git a/Output/Themes/Ambient/Screens/PopupScreenPlayerControl.xml b/Output/Themes/Ambient/Screens/PopupScreenPlayerControl.xml new file mode 100644 index 00000000..df19d2c3 --- /dev/null +++ b/Output/Themes/Ambient/Screens/PopupScreenPlayerControl.xml @@ -0,0 +1,442 @@ + + + + 1 + + + Menu + + 49 + 0 + 0,00 + 1181 + 50 + + + Visible + + + + + + + CoverBackground + + 50 + 0 + 0,00 + 50 + 50 + + + Visible + + + + + + + PreviousIcon + + PreviousIcon + + 125 + 0 + 0,00 + 50 + 50 + + + ButtonColor + + + ButtonSColor + + + 75 + 2 + + 32 + + 142 + + + ButtonTextColor + + + ButtonTextSColor + + Center + + + + Normal + + + + + + + + + + + + + PlayIcon + + PlayIcon + + 200 + 5 + 0,00 + 40 + 40 + + + ButtonColor + + + ButtonSColor + + + 75 + 2 + + 32 + + 142 + + + ButtonTextColor + + + ButtonTextSColor + + Center + + + + Normal + + + + + + + + + + + + + PauseIcon + + PauseIcon + + 200 + 5 + 0,00 + 40 + 40 + + + ButtonColor + + + ButtonSColor + + + 75 + 2 + + 32 + + 142 + + + ButtonTextColor + + + ButtonTextSColor + + Center + + + + Normal + + + + + + + + + + + + + NextIcon + + NextIcon + + 265 + 0 + 0,00 + 50 + 50 + + + ButtonColor + + + ButtonSColor + + + 190 + 25 + + 32 + + 142 + + + ButtonTextColor + + + ButtonTextSColor + + Center + + + + Normal + + + + + + + + + + + + + RepeatIcon + + RepeatIcon + + 330 + 0 + 0,00 + 50 + 50 + + + ButtonColor + + + ButtonSColor + + + 405 + 25 + + 32 + + 142 + + + ButtonTextColor + + + ButtonTextSColor + + Center + + + + Normal + + + + + + + + + + + + + VideoIcon + + VideoIcon + + 405 + 0 + 0,00 + 50 + 50 + + + ButtonColor + + + ButtonSColor + + + 315 + 0 + + 32 + + 142 + + + ButtonTextColor + + + ButtonTextSColor + + Center + + + + Normal + + + + + + + + + + + + + VideoIcon + + VideoIcon + + 480 + 0 + 0,00 + 50 + 50 + + + ButtonColor + + + ButtonSColor + + + 315 + 0 + + 32 + + 142 + + + ButtonTextColor + + + ButtonTextSColor + + Center + + + + Normal + + + + + + + + + + + + + DuetIcon + + DuetIcon + + 555 + 0 + 0,00 + 50 + 50 + + + ButtonColor + + + ButtonSColor + + + 380 + 0 + + 32 + + 142 + + + ButtonTextColor + + + ButtonTextSColor + + Center + + + + Normal + + + + + + + + + + + + + 630 + 0 + + 0,00 + + 50 + + 650 + + + StaticColor + + + TextSColor + + Left + + + + Outline + + + + + + + + \ No newline at end of file diff --git a/Output/Themes/Ambient/Screens/ScreenOptionsVideo.xml b/Output/Themes/Ambient/Screens/ScreenOptionsVideo.xml index c74bdfd3..9d8b1bc1 100644 --- a/Output/Themes/Ambient/Screens/ScreenOptionsVideo.xml +++ b/Output/Themes/Ambient/Screens/ScreenOptionsVideo.xml @@ -1,7 +1,7 @@  - 1 + 2 Video @@ -185,6 +185,33 @@ + + + 75 + 285 + + 0,00 + + 32 + + + + StaticColor + + + TextSColor + + Left + + + + Normal + + TR_SCREENO_VIDEO_VIDEOSTOBACKGROUND + + + + Button @@ -435,5 +462,70 @@ 3 + + + Invisible + + SelectSlideArrowLeft + + SelectSlideArrowRight + + SelectSlide + + SelectSlideArrowLeft + + SelectSlideArrowRight + + SelectSlide + + 500 + 280 + 0,00 + 700 + 50 + + 505 + 225 + 0,00 + 40 + 40 + + 1170 + 225 + 0,00 + 40 + 40 + + + SelectSlideColor + + + SelectSlideSColor + + + SelectSlideHColor + + + ArrowColor + + + ArrowSColor + + + TextColor + + + TextSColor + + 32,00 + + 205,33 + + Normal + + Bold + + 3 + \ No newline at end of file diff --git a/Output/Themes/Ambient/Skin Blue.xml b/Output/Themes/Ambient/Skin Blue.xml index 80bdb88c..cdf16630 100644 --- a/Output/Themes/Ambient/Skin Blue.xml +++ b/Output/Themes/Ambient/Skin Blue.xml @@ -301,6 +301,11 @@ VideoIcon.png Invisible.png PlayerSelector.png + PreviousIcon.png + NextIcon.png + PlayIcon.png + PauseIcon.png + RepeatIcon.png [Blue]BG_Video.mp4 diff --git a/Output/Themes/Ambient/Skin Green.xml b/Output/Themes/Ambient/Skin Green.xml index 095e1243..1d3893fe 100644 --- a/Output/Themes/Ambient/Skin Green.xml +++ b/Output/Themes/Ambient/Skin Green.xml @@ -301,6 +301,11 @@ VideoIcon.png Invisible.png PlayerSelector.png + PreviousIcon.png + NextIcon.png + PlayIcon.png + PauseIcon.png + RepeatIcon.png [Green]BG_Video.mp4 diff --git a/Output/Themes/Ambient/Skin Red.xml b/Output/Themes/Ambient/Skin Red.xml index c92cceda..828c675f 100644 --- a/Output/Themes/Ambient/Skin Red.xml +++ b/Output/Themes/Ambient/Skin Red.xml @@ -301,6 +301,11 @@ VideoIcon.png Invisible.png PlayerSelector.png + PreviousIcon.png + NextIcon.png + PlayIcon.png + PauseIcon.png + RepeatIcon.png [Red]BG_Video.mp4 diff --git a/Output/Themes/Ambient/Skin Yellow.xml b/Output/Themes/Ambient/Skin Yellow.xml index fbc4a227..7cbee310 100644 --- a/Output/Themes/Ambient/Skin Yellow.xml +++ b/Output/Themes/Ambient/Skin Yellow.xml @@ -301,6 +301,11 @@ VideoIcon.png Invisible.png PlayerSelector.png + PreviousIcon.png + NextIcon.png + PlayIcon.png + PauseIcon.png + RepeatIcon.png [Yellow]BG_Video.mp4 diff --git a/Output/Themes/Changelog/Changelog_ScreenOptionsVideo.txt b/Output/Themes/Changelog/Changelog_ScreenOptionsVideo.txt new file mode 100644 index 00000000..a6898ab5 --- /dev/null +++ b/Output/Themes/Changelog/Changelog_ScreenOptionsVideo.txt @@ -0,0 +1,10 @@ +ScreenOptionsTheme + +++++++++++ +Version 2: + +Add: + +and some texts and statics for description (Text5) +"TR_SCREENO_VIDEO_VIDEOSTOBACKGROUND" +++++++++++ \ No newline at end of file diff --git a/Vocaluxe/Base/CBackgroundMusic.cs b/Vocaluxe/Base/CBackgroundMusic.cs index 403a64f9..6b49ec98 100644 --- a/Vocaluxe/Base/CBackgroundMusic.cs +++ b/Vocaluxe/Base/CBackgroundMusic.cs @@ -6,6 +6,9 @@ using System.IO; using Vocaluxe.Base; using System.Diagnostics; using Vocaluxe.Lib.Song; +using Vocaluxe.Lib.Draw; +using System.Drawing; +using Vocaluxe.Menu; namespace Vocaluxe.Base { @@ -13,25 +16,140 @@ namespace Vocaluxe.Base { private static CHelper Helper = new CHelper(); private static int _CurrentMusicStream = -1; - private static string _CurrentMusicFilePath = String.Empty; - - private static List _AllFileNames = new List(); - private static List _NotPlayedFileNames = new List(); - private static List _BGMusicFileNames = new List(); + private static int _PreviousMusicIndex = 0; + private static PlaylistElement _CurrentPlaylistElement = new PlaylistElement(); + + private static List _AllFileNames = new List(); + private static List _NotPlayedFileNames = new List(); + private static List _BGMusicFileNames = new List(); + private static List _PreviousFileNames = new List(); + + private static int _Video = -1; + private static STexture _CurrentVideoTexture = new STexture(-1); + private static Stopwatch _FadeTimer = new Stopwatch(); + private static bool _VideoEnabled; private static bool _OwnMusicAdded; private static bool _BackgroundMusicAdded; private static bool _Playing; + private static bool _Disabled; + private static bool _CanSing; + + public static bool VideoEnabled + { + get + { + return _VideoEnabled; + } + set + { + if (_VideoEnabled && value) + return; + if (!_VideoEnabled && !value) + return; + if(_VideoEnabled && !value) + ToggleVideo(); + if (!_VideoEnabled && value) + ToggleVideo(); + _VideoEnabled = value; + } + } + + public static bool CanSing + { + get + { + return _CanSing; + } + + set + { + _CanSing = value; + } + } + + public static bool Disabled + { + get + { + return _Disabled; + } + set + { + _Disabled = value; + if (_Disabled) + Pause(); + else + Play(); + } + } + + public static int SongID + { + get + { + return _CurrentPlaylistElement._SongID; + } + } + + public static bool Duet + { + get + { + return _CurrentPlaylistElement.Duet; + } + } + + public static bool SongHasVideo + { + get + { + return File.Exists(_CurrentPlaylistElement.VideoFilePath); + } + } + + public static bool Playing + { + get + { + return _Playing; + } + } + + public static string ArtistAndTitle + { + get + { + return _CurrentPlaylistElement.Artist + " - " + _CurrentPlaylistElement.Title; + } + } + + public static STexture Cover + { + get + { + return _CurrentPlaylistElement.Cover; + } + } public static void Init() { - _BGMusicFileNames.AddRange(Helper.ListFiles(CSettings.sFolderBackgroundMusic, "*.mp3", true, true)); - _BGMusicFileNames.AddRange(Helper.ListFiles(CSettings.sFolderBackgroundMusic, "*.wav", true, true)); - _BGMusicFileNames.AddRange(Helper.ListFiles(CSettings.sFolderBackgroundMusic, "*.ogg", true, true)); - _BGMusicFileNames.AddRange(Helper.ListFiles(CSettings.sFolderBackgroundMusic, "*.wma", true, true)); + List templist = new List(); + + foreach(string ending in CSettings.MusicFileTypes) + { + templist.AddRange(Helper.ListFiles(CSettings.sFolderBackgroundMusic, ending, true, true)); + } + + foreach (string path in templist) + { + _BGMusicFileNames.Add(new PlaylistElement(path)); + } if(CConfig.BackgroundMusicSource != EBackgroundMusicSource.TR_CONFIG_ONLY_OWN_MUSIC) AddBackgroundMusic(); + if (CConfig.VideoBackgrounds == EOffOn.TR_CONFIG_ON) + _VideoEnabled = true; _Playing = false; } @@ -46,24 +164,42 @@ namespace Vocaluxe.Base { CSound.Fade(_CurrentMusicStream, CConfig.BackgroundMusicVolume, CSettings.BackgroundMusicFadeTime); CSound.Play(_CurrentMusicStream); + if (_VideoEnabled && _Video != -1) + CVideo.VdResume(_Video); _Playing = true; } else Next(); + + if (!IsBackgroundFile(_CurrentPlaylistElement)) + _CanSing = true; + else + _CanSing = false; } } } public static void Stop() { + if (_VideoEnabled && _Video != -1) + { + CVideo.VdClose(_Video); + CDraw.RemoveTexture(ref _CurrentVideoTexture); + _Video = -1; + } CSound.FadeAndStop(_CurrentMusicStream, 0f, CSettings.BackgroundMusicFadeTime); - _CurrentMusicFilePath = String.Empty; + _CurrentPlaylistElement = new PlaylistElement(); _Playing = false; } public static void Pause() { + if (_VideoEnabled && _Video != -1) + { + CVideo.VdPause(_Video); + CVideo.VdSkip(_Video, CSound.GetPosition(_CurrentMusicStream) + CSettings.BackgroundMusicFadeTime, _CurrentPlaylistElement.VideoGap); + } CSound.FadeAndPause(_CurrentMusicStream, 0f, CSettings.BackgroundMusicFadeTime); _Playing = false; } @@ -83,15 +219,28 @@ namespace Vocaluxe.Base { if (_AllFileNames.Count > 0) { - Stop(); + if (_PreviousMusicIndex == _PreviousFileNames.Count - 1 || _PreviousFileNames.Count == 0) //We are not currently in the previous list + { + Stop(); + if (_NotPlayedFileNames.Count == 0) + _NotPlayedFileNames.AddRange(_AllFileNames); - if (_NotPlayedFileNames.Count == 0) - _NotPlayedFileNames.AddRange(_AllFileNames); + _CurrentPlaylistElement = _NotPlayedFileNames[CGame.Rand.Next(_NotPlayedFileNames.Count)]; + _NotPlayedFileNames.Remove(_CurrentPlaylistElement); - _CurrentMusicFilePath = _NotPlayedFileNames[CGame.Rand.Next(_NotPlayedFileNames.Count)]; - _NotPlayedFileNames.Remove(_CurrentMusicFilePath); + _PreviousFileNames.Add(_CurrentPlaylistElement); + _PreviousMusicIndex = _PreviousFileNames.Count - 1; + } + else if(_PreviousFileNames.Count > 0) //We are in the previous list + { + Stop(); + _PreviousMusicIndex++; - _CurrentMusicStream = CSound.Load(_CurrentMusicFilePath); + _CurrentPlaylistElement = _PreviousFileNames[_PreviousMusicIndex]; + } + _CurrentMusicStream = CSound.Load(_CurrentPlaylistElement.MusicFilePath); + if (_VideoEnabled) + LoadVideo(); CSound.SetStreamVolume(_CurrentMusicStream, 0f); Play(); } @@ -99,6 +248,36 @@ namespace Vocaluxe.Base Stop(); } + public static void Previous() + { + if (_PreviousFileNames.Count > 0 || _PreviousMusicIndex >= 0) + { + Stop(); + + _PreviousMusicIndex--; + if (_PreviousMusicIndex < 0) + _PreviousMusicIndex = 0; //No previous songs left, so play the first + + _CurrentPlaylistElement = _PreviousFileNames[_PreviousMusicIndex]; + + _CurrentMusicStream = CSound.Load(_CurrentPlaylistElement.MusicFilePath); + if (_VideoEnabled) + LoadVideo(); + CSound.SetStreamVolume(_CurrentMusicStream, 0f); + Play(); + } + } + + public static void Repeat() + { + if (_AllFileNames.Count > 0 && _CurrentMusicStream != -1) + { + CSound.SetPosition(_CurrentMusicStream, 0); + if (_VideoEnabled && _Video != -1) + CVideo.VdSkip(_Video, 0f, _CurrentPlaylistElement.VideoGap); + } + } + public static void ApplyVolume() { CSound.SetStreamVolume(_CurrentMusicStream, CConfig.BackgroundMusicVolume); @@ -110,8 +289,8 @@ namespace Vocaluxe.Base { foreach (CSong song in CSongs.AllSongs) { - _AllFileNames.Add(song.GetMP3()); - _NotPlayedFileNames.Add(song.GetMP3()); + _AllFileNames.Add(new PlaylistElement(song)); + _NotPlayedFileNames.Add(new PlaylistElement(song)); } } _OwnMusicAdded = true; @@ -128,7 +307,7 @@ namespace Vocaluxe.Base _NotPlayedFileNames.AddRange(_BGMusicFileNames); } - if (IsPlaying() && !IsBackgroundFile(_CurrentMusicFilePath) || _AllFileNames.Count == 0) + if (Playing && !IsBackgroundFile(_CurrentPlaylistElement) || _AllFileNames.Count == 0) Next(); _OwnMusicAdded = false; @@ -153,7 +332,7 @@ namespace Vocaluxe.Base AddOwnMusic(); _BackgroundMusicAdded = false; - if (IsPlaying() && IsBackgroundFile(_CurrentMusicFilePath) || _AllFileNames.Count == 0) + if (Playing && IsBackgroundFile(_CurrentPlaylistElement) || _AllFileNames.Count == 0) Next(); } } @@ -207,19 +386,232 @@ namespace Vocaluxe.Base CConfig.SaveConfig(); } - public static bool IsPlaying() + public static void ToggleVideo() { - return CSound.IsPlaying(_CurrentMusicStream); + if (_Video != -1) + { + if (_VideoEnabled) + { + _VideoEnabled = false; + CVideo.VdClose(_Video); + _Video = -1; + CDraw.RemoveTexture(ref _CurrentVideoTexture); + return; + } + if (CVideo.VdFinished(_Video)) + { + CVideo.VdClose(_Video); + CDraw.RemoveTexture(ref _CurrentVideoTexture); + _Video = -1; + return; + } + } + else + LoadVideo(); } - private static bool IsBackgroundFile(string FilePath) + public static STexture GetVideoTexture() { - foreach (string file in _BGMusicFileNames) + if (_Video != -1) { - if (file == FilePath) + float vtime = 0f; + CVideo.VdGetFrame(_Video, ref _CurrentVideoTexture, CSound.GetPosition(_CurrentMusicStream), ref vtime); + if (_FadeTimer.ElapsedMilliseconds <= 3000L) + { + _CurrentVideoTexture.color.A = (_FadeTimer.ElapsedMilliseconds / 3000f); + } + else + { + _CurrentVideoTexture.color.A = 1f; + _FadeTimer.Stop(); + } + return _CurrentVideoTexture; + } + return new STexture(-1); + } + + private static bool IsBackgroundFile(PlaylistElement element) + { + foreach (PlaylistElement elements in _BGMusicFileNames) + { + if (elements.MusicFilePath == element.MusicFilePath) return true; } return false; } + + private static void LoadVideo() + { + if (_Video == -1) + { + _Video = CVideo.VdLoad(_CurrentPlaylistElement.VideoFilePath); + CVideo.VdSkip(_Video, 0f, _CurrentPlaylistElement.VideoGap); + _VideoEnabled = true; + _FadeTimer.Reset(); + _FadeTimer.Start(); + } + } + } +} + +class PlaylistElement +{ + public int _SongID; + private string _MusicFilePath; + + public string MusicFilePath + { + get + { + if (_SongID >= 0) + { + CSong song = CSongs.GetSong(_SongID); + if (song != null) + return song.GetMP3(); + else + { + _SongID = -1; + CLog.LogError("Song not found"); + } + } + return _MusicFilePath; + } + + set + { + _MusicFilePath = value; + } + } + + public string VideoFilePath + { + get + { + if (_SongID >= 0) + { + CSong song = CSongs.GetSong(_SongID); + if (song != null) + return song.GetVideo(); + else + { + _SongID = -1; + CLog.LogError("Song not found"); + } + } + return string.Empty; + } + } + + public string Title + { + get + { + if (_SongID >= 0) + { + CSong song = CSongs.GetSong(_SongID); + if (song != null) + return song.Title; + else + { + _SongID = -1; + CLog.LogError("Song not found"); + } + } + return "Unknown"; + } + } + + public string Artist + { + get + { + if (_SongID >= 0) + { + CSong song = CSongs.GetSong(_SongID); + if (song != null) + return song.Artist; + else + { + _SongID = -1; + CLog.LogError("Song not found"); + } + } + return "Unknown"; + } + } + + public STexture Cover + { + get + { + if (_SongID >= 0) + { + CSong song = CSongs.GetSong(_SongID); + if (song != null) + return song.CoverTextureSmall; + else + { + _SongID = -1; + CLog.LogError("Song not found"); + } + } + return CCover.NoCover; + } + } + + public float VideoGap + { + get + { + if (_SongID >= 0) + { + CSong song = CSongs.GetSong(_SongID); + if (song != null) + return song.VideoGap; + else + { + _SongID = -1; + CLog.LogError("Song not found"); + } + } + return 0; + } + } + + public bool Duet + { + get + { + if (_SongID >= 0) + { + CSong song = CSongs.GetSong(_SongID); + if (song != null) + return song.IsDuet; + else + { + _SongID = -1; + CLog.LogError("Song not found"); + } + } + return false; + } + } + + public PlaylistElement(CSong song) + { + MusicFilePath = string.Empty; + _SongID = song.ID; + } + + public PlaylistElement(string FilePath) + { + MusicFilePath = FilePath; + _SongID = -1; + } + + public PlaylistElement() + { + MusicFilePath = string.Empty; + _SongID = -1; } } diff --git a/Vocaluxe/Base/CConfig.cs b/Vocaluxe/Base/CConfig.cs index f1fc7a56..95cd1dcb 100644 --- a/Vocaluxe/Base/CConfig.cs +++ b/Vocaluxe/Base/CConfig.cs @@ -87,7 +87,8 @@ namespace Vocaluxe.Base public enum ERecordLib { - PortAudio + PortAudio, + DirectSound } public enum EVideoDecoder @@ -167,6 +168,14 @@ namespace Vocaluxe.Base TR_CONFIG_FADEPLAYERINFO_OFF } + public enum ELyricStyle + { + Fill, + Jump, + Slide, + Zoom + } + #endregion Enums static class CConfig @@ -203,6 +212,7 @@ namespace Vocaluxe.Base public static EPlayerInfo PlayerInfo = EPlayerInfo.TR_CONFIG_PLAYERINFO_BOTH; public static EFadePlayerInfo FadePlayerInfo = EFadePlayerInfo.TR_CONFIG_FADEPLAYERINFO_OFF; public static ECoverLoading CoverLoading = ECoverLoading.TR_CONFIG_COVERLOADING_ATSTART; + public static ELyricStyle LyricStyle = ELyricStyle.Slide; // Sound public static EPlaybackLib PlayBackLib = EPlaybackLib.PortAudio; @@ -230,10 +240,11 @@ namespace Vocaluxe.Base public static EOffOn VideoBackgrounds = EOffOn.TR_CONFIG_ON; public static EOffOn VideoPreview = EOffOn.TR_CONFIG_ON; public static EOffOn VideosInSongs = EOffOn.TR_CONFIG_ON; + public static EOffOn VideosToBackground = EOffOn.TR_CONFIG_OFF; // Record public static SMicConfig[] MicConfig; - public static int MicDelay = 200; //[ms] + public static int MicDelay = 300; //[ms] //Lists to save parameters and values private static List _Params = new List(); @@ -321,6 +332,7 @@ namespace Vocaluxe.Base CHelper.TryGetEnumValueFromXML("//root/Theme/PlayerInfo", navigator, ref PlayerInfo); CHelper.TryGetEnumValueFromXML("//root/Theme/FadePlayerInfo", navigator, ref FadePlayerInfo); CHelper.TryGetEnumValueFromXML("//root/Theme/CoverLoading", navigator, ref CoverLoading); + CHelper.TryGetEnumValueFromXML("//root/Theme/LyricStyle", navigator, ref LyricStyle); #endregion Theme #region Sound @@ -403,6 +415,7 @@ namespace Vocaluxe.Base CHelper.TryGetEnumValueFromXML("//root/Video/VideoBackgrounds", navigator, ref VideoBackgrounds); CHelper.TryGetEnumValueFromXML("//root/Video/VideoPreview", navigator, ref VideoPreview); CHelper.TryGetEnumValueFromXML("//root/Video/VideosInSongs", navigator, ref VideosInSongs); + CHelper.TryGetEnumValueFromXML("//root/Video/VideosToBackground", navigator, ref VideosToBackground); #endregion Video #region Record @@ -531,6 +544,9 @@ namespace Vocaluxe.Base writer.WriteComment("Cover Loading:" + ListStrings(Enum.GetNames(typeof(ECoverLoading)))); writer.WriteElementString("CoverLoading", Enum.GetName(typeof(ECoverLoading), CoverLoading)); + writer.WriteComment("Lyric Style:" + ListStrings(Enum.GetNames(typeof(ELyricStyle)))); + writer.WriteElementString("LyricStyle", Enum.GetName(typeof(ELyricStyle), LyricStyle)); + writer.WriteEndElement(); #endregion Theme @@ -635,6 +651,9 @@ namespace Vocaluxe.Base writer.WriteComment("Show Videos while singing: " + ListStrings(Enum.GetNames(typeof(EOffOn)))); writer.WriteElementString("VideosInSongs", Enum.GetName(typeof(EOffOn), VideosInSongs)); + writer.WriteComment("Show backgroundmusic videos as background: " + ListStrings(Enum.GetNames(typeof(EOffOn)))); + writer.WriteElementString("VideosToBackground", Enum.GetName(typeof(EOffOn), VideosToBackground)); + writer.WriteEndElement(); #endregion Video diff --git a/Vocaluxe/Base/CDraw.cs b/Vocaluxe/Base/CDraw.cs index 0f6d9e60..180ee03b 100644 --- a/Vocaluxe/Base/CDraw.cs +++ b/Vocaluxe/Base/CDraw.cs @@ -239,6 +239,19 @@ namespace Vocaluxe.Base _Draw.DrawTexture(Texture, rect, color, begin, end); } + public static void DrawTexture(CStatic StaticBounds, STexture Texture, EAspect Aspect) + { + RectangleF bounds = new RectangleF(StaticBounds.Rect.X, StaticBounds.Rect.Y, StaticBounds.Rect.W, StaticBounds.Rect.H); + RectangleF rect = new RectangleF(0f, 0f, Texture.width, Texture.height); + + if (rect.Height <= 0f) + return; + + CHelper.SetRect(bounds, ref rect, rect.Width / rect.Height, Aspect); + DrawTexture(Texture, new SRectF(rect.X, rect.Y, rect.Width, rect.Height, StaticBounds.Rect.Z), + Texture.color, new SRectF(bounds.X, bounds.Y, bounds.Width, bounds.Height, 0f), false); + } + public static void DrawTextureReflection(STexture Texture, SRectF rect, SColorF color, SRectF bounds, float space, float height) { _Draw.DrawTextureReflection(Texture, rect, color, bounds, space, height); diff --git a/Vocaluxe/Base/CGame.cs b/Vocaluxe/Base/CGame.cs index 26009db5..f0cf4245 100644 --- a/Vocaluxe/Base/CGame.cs +++ b/Vocaluxe/Base/CGame.cs @@ -16,6 +16,8 @@ namespace Vocaluxe.Base public string Name; public EGameDifficulty Difficulty; public double Points; + public double PointsLineBonus; + public double PointsGoldenNotes; public int NoteDiff; public int LineNr; public List SingLine; @@ -215,6 +217,8 @@ namespace Vocaluxe.Base for (int i = 0; i < _Player.Length; i++) { _Player[i].Points = 0f; + _Player[i].PointsLineBonus = 0f; + _Player[i].PointsGoldenNotes = 0f; _Player[i].LineNr = 0; _Player[i].NoteDiff = 0; _Player[i].SingLine = new List(); @@ -249,7 +253,7 @@ namespace Vocaluxe.Base CSound.AnalyzeBuffer(p); } - if (_OldBeatD == _CurrentBeatD) + if (_OldBeatD >= _CurrentBeatD) return; for (int p = 0; p < _NumPlayer; p++) @@ -323,8 +327,12 @@ namespace Vocaluxe.Base if (_Player[p].NoteDiff <= (2 - (int)_Player[p].Difficulty)) { // valid - CSound.RecordSetTone(p, Tone); - _Player[p].Points += (CSettings.MaxScore - CSettings.LinebonusScore) * (double)notes[Note].PointsForBeat / (double)song.Notes.GetLines(_Player[p].LineNr).Points; + //CSound.RecordSetTone(p, Tone); + double points = (CSettings.MaxScore - CSettings.LinebonusScore) * (double)notes[Note].PointsForBeat / (double)song.Notes.GetLines(_Player[p].LineNr).Points; + if (notes[Note].NoteType == ENoteType.Golden) + _Player[p].PointsGoldenNotes += points; + + _Player[p].Points += points; // update player notes (sung notes) if (_Player[p].SingLine[Line].NoteCount > 0) @@ -344,11 +352,6 @@ namespace Vocaluxe.Base _Player[p].SingLine[Line].LastNote.IsPerfect(notes[Note]); _Player[p].SingLine[Line].IsPerfect(lines[Line]); - - if (_Player[p].SingLine[Line].PerfectLine) - { - _Player[p].Points += CSettings.LinebonusScore * (double)lines[Line].Points / (double)song.Notes.GetPoints(_Player[p].LineNr); - } } else { @@ -356,7 +359,7 @@ namespace Vocaluxe.Base { CNote nt = _Player[p].SingLine[Line].LastNote; if (nt.EndBeat + 1 != beat || nt.Hit) - _Player[p].SingLine[Line].AddNote(new CNote(beat, 1, TonePlayer, String.Empty, false, notes[Note].NoteType)); + _Player[p].SingLine[Line].AddNote(new CNote(beat, 1, TonePlayer, String.Empty, false, ENoteType.Freestyle)); else { if (nt.Tone == TonePlayer && nt.EndBeat + 1 == beat) @@ -365,17 +368,41 @@ namespace Vocaluxe.Base } else { - _Player[p].SingLine[Line].AddNote(new CNote(beat, 1, TonePlayer, String.Empty, false, notes[Note].NoteType)); + _Player[p].SingLine[Line].AddNote(new CNote(beat, 1, TonePlayer, String.Empty, false, ENoteType.Freestyle)); } } } else { - _Player[p].SingLine[Line].AddNote(new CNote(beat, 1, TonePlayer, String.Empty, false, notes[Note].NoteType)); + _Player[p].SingLine[Line].AddNote(new CNote(beat, 1, TonePlayer, String.Empty, false, ENoteType.Freestyle)); } } } + + // Line Bonus + int NumLinesWithPoints = song.Notes.GetNumLinesWithPoints(_Player[p].LineNr); + if (Note == lines[Line].NoteCount - 1 && NumLinesWithPoints > 0) + { + if (notes[Note].EndBeat == beat && lines[Line].Points > 0f) + { + double factor = (double)_Player[p].SingLine[Line].Points / (double)lines[Line].Points; + if (factor < 0.4) + factor = 0.0; + else if (factor > 0.9) + factor = 1.0; + else + { + factor -= 0.4; + factor *= 2; + factor *= factor; + } + + double points = CSettings.LinebonusScore * factor * 1f / NumLinesWithPoints; + _Player[p].Points += points; + _Player[p].PointsLineBonus += points; + } + } } } diff --git a/Vocaluxe/Base/CSettings.cs b/Vocaluxe/Base/CSettings.cs index 049edfc0..67359b9b 100644 --- a/Vocaluxe/Base/CSettings.cs +++ b/Vocaluxe/Base/CSettings.cs @@ -47,7 +47,7 @@ namespace Vocaluxe.Base public const int iVersionSub = 0; // patches public const ERevision VersionRevision = ERevision.Alpha; - public const int iBuild = 62; // Increase on every published version! Never Reset! + public const int iBuild = 63; // Increase on every published version! Never Reset! public const int iDatabaseHighscoreVersion = 1; public const int iDatabaseCoverVersion = 1; @@ -115,6 +115,11 @@ namespace Vocaluxe.Base public static bool TabNavigation = false; public const float BackgroundMusicFadeTime = 0.5f; + + public static List MusicFileTypes = new List() + { + "*.mp3","*.wma","*.ogg","*.wav" + }; public static string GetVersionText() { diff --git a/Vocaluxe/Base/CSound.cs b/Vocaluxe/Base/CSound.cs index 440d405d..71c6fd59 100644 --- a/Vocaluxe/Base/CSound.cs +++ b/Vocaluxe/Base/CSound.cs @@ -181,6 +181,9 @@ namespace Vocaluxe.Base case ERecordLib.PortAudio: _Record = new CPortAudioRecord(); break; + case ERecordLib.DirectSound: + _Record = new CDirectSoundRecord(); + break; default: _Record = new CPortAudioRecord(); @@ -237,6 +240,16 @@ namespace Vocaluxe.Base return _Record.GetMaxVolume(Player); } + public static int NumHalfTones(int Player) + { + return _Record.NumHalfTones(Player); + } + + public static float[] ToneWeigth(int Player) + { + return _Record.ToneWeigth(Player); + } + public static SRecordDevice[] RecordGetDevices() { SRecordDevice[] devices = _Record.RecordDevices(); @@ -281,9 +294,10 @@ namespace Vocaluxe.Base class CBuffer { - private const double BaseToneFreq = 65.4064; - private const int NumHalfTones = 47; + private const double _BaseToneFreq = 65.4064; + private const int _NumHalfTones = 47; + private float[] _ToneWeigth; private Int16[] _AnalysisBuffer = new Int16[4096]; private Object _AnalysisBufferLock = new Object(); @@ -291,10 +305,22 @@ namespace Vocaluxe.Base private int _Tone = 0; private int _ToneAbs = 0; private double _MaxVolume = 0.0; - private bool _NewSamples = false; + private bool _NewSamples; private MemoryStream _Stream; // full buffer + public CBuffer() + { + _ToneWeigth = new float[_NumHalfTones]; + _Stream = new MemoryStream(); + _NewSamples = false; + } + + public int NumHalfTones + { + get { return _NumHalfTones; } + } + public int ToneAbs { get @@ -346,11 +372,6 @@ namespace Vocaluxe.Base } } - public CBuffer() - { - _Stream = new MemoryStream(); - } - public long Length { get { return _Stream.Length; } @@ -361,6 +382,17 @@ namespace Vocaluxe.Base get { return _Stream.ToArray(); } } + public float[] ToneWeigth + { + get + { + lock (_AnalysisBufferLock) + { + return _ToneWeigth; + } + } + } + public void Reset() { _Stream.SetLength(0L); @@ -386,39 +418,8 @@ namespace Vocaluxe.Base //if (assigned(fVoiceStream)) then //fVoiceStream.WriteData(Buffer, BufferSize); - int BufferOffset = 0; - int SampleCount = (int)Math.Floor(buffer.Length / 2.0); - - if (SampleCount > _AnalysisBuffer.Length) - { - BufferOffset = (SampleCount - _AnalysisBuffer.Length) * 2; - SampleCount = _AnalysisBuffer.Length; - } - lock (_AnalysisBufferLock) { - try - { - // move old samples to the beginning of the array (if necessary) - for (int i = 0; i < _AnalysisBuffer.Length - SampleCount; i++) - { - _AnalysisBuffer[i] = _AnalysisBuffer[i + SampleCount]; - } - - byte[] b = new byte[2]; - // copy new samples to analysis buffer - for (int i = 0; i < SampleCount; i++) - { - b[0] = buffer[BufferOffset + i * 2]; - b[1] = buffer[BufferOffset + i * 2 + 1]; - - _AnalysisBuffer[_AnalysisBuffer.Length - SampleCount + i] = BitConverter.ToInt16(b, 0); - } - } - catch (Exception) - { - - } Add(buffer); _NewSamples = true; } @@ -426,69 +427,98 @@ namespace Vocaluxe.Base public void AnalyzeBuffer() { + if (!_NewSamples) + return; + lock (_AnalysisBufferLock) { - if (!_NewSamples) - return; - - try + int len = _AnalysisBuffer.Length * 2; + if (_Stream.Length >= len) { - // find maximum volume - _MaxVolume = 0; - for (int i = 0; i < _AnalysisBuffer.Length/4; i++) - { - float Volume = Math.Abs((float)_AnalysisBuffer[i]) / (float)Int16.MaxValue; - if (Volume > MaxVolume) - _MaxVolume = Volume; - } + byte[] buf = new byte[len]; + _Stream.Position -= len; + _Stream.Read(buf, 0, len); - if (_MaxVolume >= 0.05f) + byte[] b = new byte[2]; + for (int i = 0; i < _AnalysisBuffer.Length; i++) { - // analyse the current voice pitch - AnalyzeByAutocorrelation(); - _ToneValid = true; - } - else - _ToneValid = false; + b[0] = buf[i * 2]; + b[1] = buf[i * 2 + 1]; - _NewSamples = false; + _AnalysisBuffer[i] = BitConverter.ToInt16(b, 0); + } } - catch (Exception) + _NewSamples = false; + } + + try + { + // find maximum volume + _MaxVolume = 0; + for (int i = 0; i < _AnalysisBuffer.Length / 4; i++) { - + float Volume = Math.Abs((float)_AnalysisBuffer[i]) / (float)Int16.MaxValue; + if (Volume > MaxVolume) + _MaxVolume = Volume; } + + if (_MaxVolume >= 0.02f) + AnalyzeByAutocorrelation(true); + else + AnalyzeByAutocorrelation(false); + + } + catch (Exception) + { + } } - private void AnalyzeByAutocorrelation() + private void AnalyzeByAutocorrelation(bool valid) { const double HalftoneBase = 1.05946309436; // 2^(1/12) -> HalftoneBase^12 = 2 (one octave) // prepare to analyze double MaxWeight = -1.0; - int MaxTone = 0; + double MinWeight = 1.0; + int MaxTone = -1; + float[] 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 CurFreq = _BaseToneFreq * Math.Pow(HalftoneBase, ToneIndex); double CurWeight = AnalyzeAutocorrelationFreq(CurFreq); - // TODO: prefer higher frequencies (use >= or use downto) - if (CurWeight > MaxWeight /* && (Math.Abs(ToneIndex - _ToneAbs) < 5 || _ToneAbs == 0)*/) + if (CurWeight > MaxWeight) { - // this frequency has a higher weight MaxWeight = CurWeight; MaxTone = ToneIndex; } + + if (CurWeight < MinWeight) + MinWeight = CurWeight; + + Weigth[ToneIndex] = (float)CurWeight; } - _ToneAbs = MaxTone; - _Tone = MaxTone % 12; + if (valid && MaxWeight - MinWeight > 0.01) + { + for (int i = 0; i < Weigth.Length; i++) + { + _ToneWeigth[i] = Weigth[i]; + } + + _ToneAbs = MaxTone; + _Tone = MaxTone % 12; + _ToneValid = true; + } + else + _ToneValid = false; } private double AnalyzeAutocorrelationFreq(double Freq) diff --git a/Vocaluxe/GameModes/CGameMode.cs b/Vocaluxe/GameModes/CGameMode.cs index 821178e4..15a534a9 100644 --- a/Vocaluxe/GameModes/CGameMode.cs +++ b/Vocaluxe/GameModes/CGameMode.cs @@ -22,7 +22,9 @@ namespace Vocaluxe.GameModes _Rounds[round, player].ProfileID = Player[player].ProfileID; _Rounds[round, player].Name = Player[player].Name; _Rounds[round, player].Difficulty = Player[player].Difficulty; - _Rounds[round, player].Points = 0; + _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].SongFinished = false; @@ -38,6 +40,8 @@ namespace Vocaluxe.GameModes _Rounds[Round, player].SongID = SongID; _Rounds[Round, player].LineNr = Player[player].LineNr; _Rounds[Round, player].Points = Player[player].Points; + _Rounds[Round, player].PointsGoldenNotes = Player[player].PointsGoldenNotes; + _Rounds[Round, player].PointsLineBonus = Player[player].PointsLineBonus; _Rounds[Round, player].Medley = Medley; _Rounds[Round, player].Duet = Duet; _Rounds[Round, player].DateTicks = DateTicks; @@ -68,6 +72,8 @@ namespace Vocaluxe.GameModes { player[p].Name = _Rounds[Round, p].Name; player[p].Points = _Rounds[Round, p].Points; + player[p].PointsGoldenNotes = _Rounds[Round, p].PointsGoldenNotes; + player[p].PointsLineBonus = _Rounds[Round, p].PointsLineBonus; player[p].SongID = _Rounds[Round, p].SongID; player[p].LineNr = _Rounds[Round, p].LineNr; player[p].Difficulty = _Rounds[Round, p].Difficulty; diff --git a/Vocaluxe/Lib/Song/CNotes.cs b/Vocaluxe/Lib/Song/CNotes.cs index 43bb7a29..edd3b6d3 100644 --- a/Vocaluxe/Lib/Song/CNotes.cs +++ b/Vocaluxe/Lib/Song/CNotes.cs @@ -33,6 +33,14 @@ namespace Vocaluxe.Lib.Song return _Lines[Index].Points; } + public int GetNumLinesWithPoints(int Index) + { + if (Index >= _Lines.Count) + return 0; + + return _Lines[Index].NumLinesWithPoints; + } + public void AddLines(CLines Lines) { _Lines.Add(Lines); @@ -545,6 +553,20 @@ namespace Vocaluxe.Lib.Song } } + public int NumLinesWithPoints + { + get + { + int num = 0; + foreach (CLine line in _Lines) + { + if (line.Points > 0f) + num++; + } + return num; + } + } + #region Methods public void AddLine(CLine Line) { diff --git a/Vocaluxe/Lib/Song/CSong.cs b/Vocaluxe/Lib/Song/CSong.cs index 60fb2049..dce672c1 100644 --- a/Vocaluxe/Lib/Song/CSong.cs +++ b/Vocaluxe/Lib/Song/CSong.cs @@ -121,6 +121,11 @@ namespace Vocaluxe.Lib.Song return Path.Combine(Folder, MP3FileName); } + public string GetVideo() + { + return Path.Combine(Folder, VideoFileName); + } + public bool ReadTXTSong(string FilePath) { if (!File.Exists(FilePath)) diff --git a/Vocaluxe/Lib/Sound/CDirectSoundRecord.cs b/Vocaluxe/Lib/Sound/CDirectSoundRecord.cs new file mode 100644 index 00000000..c8abe845 --- /dev/null +++ b/Vocaluxe/Lib/Sound/CDirectSoundRecord.cs @@ -0,0 +1,437 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using SlimDX.DirectSound; +using SlimDX.Multimedia; +using Vocaluxe.Base; + +namespace Vocaluxe.Lib.Sound +{ + class CDirectSoundRecord : IRecord + { + private bool _initialized = false; + private List _Devices = null; + private SRecordDevice[] _DeviceConfig = null; + private List _Sources = null; + + private CBuffer[] _Buffer; + + public CDirectSoundRecord() + { + _Buffer = new CBuffer[CSettings.MaxNumPlayer]; + for (int i = 0; i < _Buffer.Length; i++) + { + _Buffer[i] = new CBuffer(); + } + + Init(); + } + + public bool Init() + { + DeviceCollection devices = DirectSoundCapture.GetDevices(); + _Devices = new List(); + _Sources = new List(); + + int id = 0; + foreach (DeviceInformation dev in devices) + { + DirectSoundCapture ds = new DirectSoundCapture(dev.DriverGuid); + + SRecordDevice device = new SRecordDevice(); + device.Driver = dev.DriverGuid.ToString(); + device.ID = id; + device.Name = dev.Description; + device.Inputs = new List(); + + SInput inp = new SInput(); + inp.Name = "Default"; + inp.Channels = ds.Capabilities.Channels; + + if (inp.Channels > 2) + inp.Channels = 2; //more are not supported in vocaluxe + + device.Inputs.Add(inp); + _Devices.Add(device); + + id++; + ds.Dispose(); + } + + _DeviceConfig = _Devices.ToArray(); + _initialized = true; + + return true; + } + + public void CloseAll() + { + if (_initialized) + { + foreach (SoundCardSource source in _Sources) + { + source.Stop(); + source.Dispose(); + } + _initialized = false; + } + //System.IO.File.WriteAllBytes("test0.raw", _Buffer[0].Buffer); + } + + public bool Start(SRecordDevice[] DeviceConfig) + { + if (!_initialized) + return false; + + for (int i = 0; i < _Buffer.Length; i++) + { + _Buffer[i].Reset(); + } + + _DeviceConfig = DeviceConfig; + bool[] active = new bool[DeviceConfig.Length]; + Guid[] guid = new Guid[DeviceConfig.Length]; + short[] channels = new short[DeviceConfig.Length]; + for (int dev = 0; dev < DeviceConfig.Length; dev++) + { + active[dev] = false; + for (int inp = 0; inp < DeviceConfig[dev].Inputs.Count; inp++) + { + if (DeviceConfig[dev].Inputs[inp].PlayerChannel1 > 0 || + DeviceConfig[dev].Inputs[inp].PlayerChannel2 > 0) + active[dev] = true; + guid[dev] = new Guid(DeviceConfig[dev].Driver); + channels[dev] = (short)DeviceConfig[dev].Inputs[0].Channels; + } + } + + for (int i = 0; i < _Devices.Count; i++) + { + if (active[i]) + { + SoundCardSource source = new SoundCardSource(guid[i], channels[i]); + source.SampleRateKHz = 44.1; + source.SampleDataReady += this.OnDataReady; + source.Start(); + + _Sources.Add(source); + + } + } + + _DeviceConfig = DeviceConfig; + return true; + } + + public bool Stop() + { + if (!_initialized) + return false; + + foreach (SoundCardSource source in _Sources) + { + source.Stop(); + } + return true; + } + public void AnalyzeBuffer(int Player) + { + if (!_initialized) + return; + + _Buffer[Player].AnalyzeBuffer(); + } + + public int GetToneAbs(int Player) + { + if (!_initialized) + return 0; + + return _Buffer[Player].ToneAbs; + } + + public int GetTone(int Player) + { + if (!_initialized) + return 0; + + return _Buffer[Player].Tone; + } + + public void SetTone(int Player, int Tone) + { + if (!_initialized) + return; + + _Buffer[Player].Tone = Tone; + } + + public float GetMaxVolume(int Player) + { + if (!_initialized) + return 0f; + + return _Buffer[Player].MaxVolume; + } + + public bool ToneValid(int Player) + { + if (!_initialized) + return false; + + return _Buffer[Player].ToneValid; + } + + public SRecordDevice[] RecordDevices() + { + if (!_initialized) + return null; + + if (_Devices.Count == 0) + return null; + + return _Devices.ToArray(); + } + + public int NumHalfTones(int Player) + { + if (!_initialized) + return 0; + + return _Buffer[Player].NumHalfTones; + } + + public float[] ToneWeigth(int Player) + { + if (!_initialized) + return null; + + return _Buffer[Player].ToneWeigth; + } + + private void OnDataReady(object sender, SampleDataEventArgs e) + { + if (_initialized) + { + byte[] _leftBuffer = new byte[e.Data.Length / 2]; + byte[] _rightBuffer = new byte[e.Data.Length / 2]; + + //[]: Sample, L: Left channel R: Right channel + //[LR][LR][LR][LR][LR][LR] + //The data is interleaved and needs to be demultiplexed + for (int i = 0; i < e.Data.Length / 2; i++) + { + _leftBuffer[i] = e.Data[i * 2 - (i % 2)]; + _rightBuffer[i] = e.Data[i * 2 - (i % 2) + 2]; + } + + for (int i = 0; i < _DeviceConfig.Length; i++) + { + if (_DeviceConfig[i].Driver == e.Guid.ToString()) + { + if (_DeviceConfig[i].Inputs[0].PlayerChannel1 > 0) + _Buffer[_DeviceConfig[i].Inputs[0].PlayerChannel1 - 1].ProcessNewBuffer(_leftBuffer); + + if (_DeviceConfig[i].Inputs[0].PlayerChannel2 > 0) + _Buffer[_DeviceConfig[i].Inputs[0].PlayerChannel2 - 1].ProcessNewBuffer(_rightBuffer); + } + } + } + } + + public class SampleDataEventArgs : EventArgs + { + public SampleDataEventArgs(byte[] data, Guid guid) + { + this.Data = data; + this.Guid = guid; + } + + public byte[] Data { get; private set; } + public Guid Guid { get; private set; } + } + + public class SoundCardSource : IDisposable + { + private volatile bool running; + private int bufferSize; + private CaptureBuffer buffer; + private CaptureBufferDescription bufferDescription; + private DirectSoundCapture captureDevice; + private WaveFormat waveFormat; + private Thread captureThread; + private List notifications; + private int bufferPortionCount; + private int bufferPortionSize; + private WaitHandle[] waitHandles; + private double sampleRate; + private Guid guid; + private short channels; + + public SoundCardSource(Guid guid, short channels) + { + this.guid = guid; + this.channels = channels; + this.waveFormat = new WaveFormat(); + this.SampleRateKHz = 44.1; + this.bufferSize = 2048; + } + + public event EventHandler SampleDataReady = delegate { }; + + public double SampleRateKHz + { + get + { + return this.sampleRate; + } + + set + { + this.sampleRate = value; + + if (this.running) + { + this.Restart(); + } + } + } + + public void Start() + { + if (this.running) + { + throw new InvalidOperationException(); + } + + if (this.captureDevice == null) + { + this.captureDevice = new DirectSoundCapture(guid); + } + + this.waveFormat.FormatTag = WaveFormatTag.Pcm; // Change to WaveFormatTag.IeeeFloat for float + this.waveFormat.BitsPerSample = 16; // Set this to 32 for float + this.waveFormat.BlockAlignment = (short)(channels * (waveFormat.BitsPerSample / 8)); + this.waveFormat.Channels = this.channels; + this.waveFormat.SamplesPerSecond = (int)(this.SampleRateKHz * 1000D); + this.waveFormat.AverageBytesPerSecond = + this.waveFormat.SamplesPerSecond * + this.waveFormat.BlockAlignment; + + this.bufferPortionCount = 2; + + this.bufferDescription.BufferBytes = this.bufferSize * sizeof(short) * bufferPortionCount * this.channels; + this.bufferDescription.Format = this.waveFormat; + this.bufferDescription.WaveMapped = false; + + this.buffer = new CaptureBuffer(this.captureDevice, this.bufferDescription); + + this.bufferPortionSize = this.buffer.SizeInBytes / this.bufferPortionCount; + this.notifications = new List(); + + for (int i = 0; i < this.bufferPortionCount; i++) + { + NotificationPosition notification = new NotificationPosition(); + notification.Offset = this.bufferPortionCount - 1 + (bufferPortionSize * i); + notification.Event = new AutoResetEvent(false); + this.notifications.Add(notification); + } + + this.buffer.SetNotificationPositions(this.notifications.ToArray()); + this.waitHandles = new WaitHandle[this.notifications.Count]; + + for (int i = 0; i < this.notifications.Count; i++) + { + this.waitHandles[i] = this.notifications[i].Event; + } + + this.captureThread = new Thread(new ThreadStart(this.CaptureThread)); + this.captureThread.IsBackground = true; + + this.running = true; + this.captureThread.Start(); + } + + public void Stop() + { + this.running = false; + + if (this.captureThread != null) + { + this.captureThread.Join(); + this.captureThread = null; + } + + if (this.buffer != null) + { + this.buffer.Dispose(); + this.buffer = null; + } + + if (this.notifications != null) + { + for (int i = 0; i < this.notifications.Count; i++) + { + this.notifications[i].Event.Close(); + } + + this.notifications.Clear(); + this.notifications = null; + } + } + + public void Restart() + { + this.Stop(); + this.Start(); + } + + private void CaptureThread() + { + int bufferPortionSamples = this.bufferPortionSize / sizeof(byte); + + // Buffer type must match this.waveFormat.FormatTag and this.waveFormat.BitsPerSample + byte[] bufferPortion = new byte[bufferPortionSamples]; + int bufferPortionIndex; + + this.buffer.Start(true); + + while (this.running) + { + bufferPortionIndex = WaitHandle.WaitAny(this.waitHandles); + + this.buffer.Read( + bufferPortion, + 0, + bufferPortionSamples, + bufferPortionSize * Math.Abs((bufferPortionIndex - 1) % bufferPortionCount)); + + this.SampleDataReady(this, new SampleDataEventArgs(bufferPortion, guid)); + } + + this.buffer.Stop(); + } + + public void Dispose() + { + this.Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + this.Stop(); + + if (this.captureDevice != null) + { + this.captureDevice.Dispose(); + this.captureDevice = null; + } + } + } + } + + } +} diff --git a/Vocaluxe/Lib/Sound/CPortAudioRecord.cs b/Vocaluxe/Lib/Sound/CPortAudioRecord.cs index 87bff1ab..884886cb 100644 --- a/Vocaluxe/Lib/Sound/CPortAudioRecord.cs +++ b/Vocaluxe/Lib/Sound/CPortAudioRecord.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Runtime.InteropServices; using System.Text; @@ -90,6 +91,7 @@ namespace Vocaluxe.Lib.Sound CLog.LogError("Error initializing PortAudio: " + e.Message); return false; } + return true; } @@ -103,6 +105,15 @@ namespace Vocaluxe.Lib.Sound if (!_initialized) return false; + if (DeviceConfig == null) + return false; + + if (_recHandle == null) + return false; + + if (_recHandle.Length == 0) + return false; + for (int i = 0; i < _Buffer.Length; i++) { _Buffer[i].Reset(); @@ -142,7 +153,7 @@ namespace Vocaluxe.Lib.Sound ref inputParams, IntPtr.Zero, 44100, - PortAudio.paFramesPerBufferUnspecified, + 882, PortAudio.PaStreamFlags.paNoFlag, _myRecProc, new IntPtr(i)))) @@ -152,7 +163,6 @@ namespace Vocaluxe.Lib.Sound return false; } } - return result; } @@ -240,6 +250,22 @@ namespace Vocaluxe.Lib.Sound return _Buffer[Player].ToneValid; } + public int NumHalfTones(int Player) + { + if (!_initialized) + return 0; + + return _Buffer[Player].NumHalfTones; + } + + public float[] ToneWeigth(int Player) + { + if (!_initialized) + return null; + + return _Buffer[Player].ToneWeigth; + } + public SRecordDevice[] RecordDevices() { if (!_initialized) diff --git a/Vocaluxe/Lib/Sound/IRecord.cs b/Vocaluxe/Lib/Sound/IRecord.cs index e4b9cc2b..3b664a71 100644 --- a/Vocaluxe/Lib/Sound/IRecord.cs +++ b/Vocaluxe/Lib/Sound/IRecord.cs @@ -51,6 +51,8 @@ namespace Vocaluxe.Lib.Sound void SetTone(int Player, int Tone); float GetMaxVolume(int Player); bool ToneValid(int Player); + int NumHalfTones(int Player); + float[] ToneWeigth(int Player); SRecordDevice[] RecordDevices(); } diff --git a/Vocaluxe/Menu/CBackground.cs b/Vocaluxe/Menu/CBackground.cs index c6adfa33..cedc4eb5 100644 --- a/Vocaluxe/Menu/CBackground.cs +++ b/Vocaluxe/Menu/CBackground.cs @@ -137,8 +137,16 @@ namespace Vocaluxe.Menu public bool Draw() { bool ok = false; - if (_Theme.Type == EBackgroundTypes.Video && CConfig.VideoBackgrounds == EOffOn.TR_CONFIG_ON) + if (_Theme.Type == EBackgroundTypes.Video && CConfig.VideoBackgrounds == EOffOn.TR_CONFIG_ON && CConfig.VideosToBackground == EOffOn.TR_CONFIG_ON && CBackgroundMusic.Playing && CBackgroundMusic.SongHasVideo && CBackgroundMusic.VideoEnabled && !CBackgroundMusic.Disabled) + { + Pause(); + ok = DrawBackgroundMusicVideo(); + } + else if (_Theme.Type == EBackgroundTypes.Video && CConfig.VideoBackgrounds == EOffOn.TR_CONFIG_ON) + { + Resume(); ok = DrawVideo(); + } if (_Theme.TextureName != String.Empty && (_Theme.Type == EBackgroundTypes.Texture || @@ -206,6 +214,21 @@ namespace Vocaluxe.Menu } return false; } + + private bool DrawBackgroundMusicVideo() + { + STexture VideoTexture = CBackgroundMusic.GetVideoTexture(); + if (VideoTexture.height > 0) + { + RectangleF bounds = new RectangleF(0f, 0f, CSettings.iRenderW, CSettings.iRenderH); + RectangleF rect = new RectangleF(0f, 0f, VideoTexture.width, VideoTexture.height); + CHelper.SetRect(bounds, ref rect, rect.Width / rect.Height, EAspect.Crop); + + CDraw.DrawTexture(VideoTexture, new SRectF(rect.X, rect.Y, rect.Width, rect.Height, CSettings.zFar / 4)); + return true; + } + return false; + } #endregion internal #region ThemeEdit diff --git a/Vocaluxe/Menu/CButton.cs b/Vocaluxe/Menu/CButton.cs index 0341bf03..d4b5d231 100644 --- a/Vocaluxe/Menu/CButton.cs +++ b/Vocaluxe/Menu/CButton.cs @@ -41,6 +41,7 @@ namespace Vocaluxe.Menu public float SReflectionHeight; private bool _Selected; + public bool Pressed; public bool Selected { get { return _Selected; } @@ -234,7 +235,8 @@ namespace Vocaluxe.Menu return; STexture texture = new STexture(-1); - if (!Selected) + + if (!Selected && !Pressed) { texture = CTheme.GetSkinTexture(_Theme.TextureName); CDraw.DrawTexture(texture, Rect, Color); diff --git a/Vocaluxe/Menu/CGraphics.cs b/Vocaluxe/Menu/CGraphics.cs index cd3148de..3472f122 100644 --- a/Vocaluxe/Menu/CGraphics.cs +++ b/Vocaluxe/Menu/CGraphics.cs @@ -36,6 +36,13 @@ namespace Vocaluxe.Menu ScreenNull = -1 } + enum EPopupScreens + { + PopupPlayerControl = 0, + + NoPopup = -1 + } + class CCursor { private Stopwatch _CursorFadingTimer; @@ -185,11 +192,12 @@ namespace Vocaluxe.Menu private static float _GlobalAlpha; private static float _ZOffset; - private static EScreens ActualScreen; - private static EScreens NextScreen; + private static EScreens _CurrentScreen; + private static EScreens _NextScreen; + private static EPopupScreens _CurrentPopupScreen; - private static List ScreenList = new List(); - private static CMenu[] Screens; + private static List _Screens = new List(); + private static List _PopupScreens = new List(); public static float GlobalAlpha { @@ -206,28 +214,31 @@ namespace Vocaluxe.Menu { // Add Screens, must be the same order as in EScreens! CLog.StartBenchmark(1, "Build Screen List"); - ScreenList.Add(new CScreenTest()); - ScreenList.Add(new CScreenLoad()); - ScreenList.Add(new CScreenMain()); - ScreenList.Add(new CScreenSong()); - ScreenList.Add(new CScreenOptions()); - ScreenList.Add(new CScreenSing()); - ScreenList.Add(new CScreenProfiles()); - ScreenList.Add(new CScreenScore()); - ScreenList.Add(new CScreenHighscore()); - ScreenList.Add(new CScreenOptionsGame()); - ScreenList.Add(new CScreenOptionsSound()); - ScreenList.Add(new CScreenOptionsRecord()); - 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(); + _Screens.Add(new CScreenTest()); + _Screens.Add(new CScreenLoad()); + _Screens.Add(new CScreenMain()); + _Screens.Add(new CScreenSong()); + _Screens.Add(new CScreenOptions()); + _Screens.Add(new CScreenSing()); + _Screens.Add(new CScreenProfiles()); + _Screens.Add(new CScreenScore()); + _Screens.Add(new CScreenHighscore()); + _Screens.Add(new CScreenOptionsGame()); + _Screens.Add(new CScreenOptionsSound()); + _Screens.Add(new CScreenOptionsRecord()); + _Screens.Add(new CScreenOptionsVideo()); + _Screens.Add(new CScreenOptionsTheme()); + _Screens.Add(new CScreenNames()); + _Screens.Add(new CScreenCredits()); + + _PopupScreens.Add(new CPopupScreenPlayerControl()); + + CLog.StopBenchmark(1, "Build Screen List"); - ActualScreen = EScreens.ScreenLoad; - NextScreen = EScreens.ScreenNull; + _CurrentScreen = EScreens.ScreenLoad; + _NextScreen = EScreens.ScreenNull; + _CurrentPopupScreen = EPopupScreens.NoPopup; _FadingTimer = new Stopwatch(); _GlobalAlpha = 1f; @@ -247,50 +258,65 @@ namespace Vocaluxe.Menu CTheme.Cursor.h, CSettings.zNear); - for (int i = 0; i < Screens.Length; i++) + for (int i = 0; i < _Screens.Count; i++) { CLog.StartBenchmark(1, "Load Theme " + Enum.GetNames(typeof(EScreens))[i]); - Screens[i].LoadTheme(); + _Screens[i].LoadTheme(); CLog.StopBenchmark(1, "Load Theme " + Enum.GetNames(typeof(EScreens))[i]); } + + for (int i = 0; i < _PopupScreens.Count; i++) + { + _PopupScreens[i].LoadTheme(); + } } public static void ReloadTheme() { ReloadCursor(); - for (int i = 0; i < Screens.Length; i++) + for (int i = 0; i < _Screens.Count; i++) { - Screens[i].ReloadTheme(); + _Screens[i].ReloadTheme(); } + + for (int i = 0; i < _PopupScreens.Count; i++) + { + _PopupScreens[i].ReloadTheme(); + } } public static void ReloadSkin() { ReloadCursor(); - for (int i = 0; i < Screens.Length; i++) + for (int i = 0; i < _Screens.Count; i++) { - Screens[i].ReloadTextures(); + _Screens[i].ReloadTextures(); } + + for (int i = 0; i < _PopupScreens.Count; i++) + { + _PopupScreens[i].ReloadTextures(); + } } public static void SaveTheme() { CTheme.SaveTheme(); - for (int i = 0; i < Screens.Length; i++) + for (int i = 0; i < _Screens.Count; i++) { - Screens[i].SaveTheme(); + _Screens[i].SaveTheme(); } + + for (int i = 0; i < _PopupScreens.Count; i++) + { + _PopupScreens[i].SaveTheme(); + } } public static void InitFirstScreen() { - Screens[(int)ActualScreen].OnShow(); - Screens[(int)ActualScreen].OnShowFinish(); - } - - public static CMenu GetScreen(int Index) - { - return Screens[Index]; + _Screens[(int)_CurrentScreen].OnShow(); + _Screens[(int)_CurrentScreen].OnShowFinish(); } public static bool UpdateGameLogic(CKeys Keys, CMouse Mouse) @@ -304,7 +330,7 @@ namespace Vocaluxe.Menu CSound.Update(); CBackgroundMusic.Update(); - if (CConfig.CoverLoading == ECoverLoading.TR_CONFIG_COVERLOADING_DYNAMIC && ActualScreen != EScreens.ScreenSing) + if (CConfig.CoverLoading == ECoverLoading.TR_CONFIG_COVERLOADING_DYNAMIC && _CurrentScreen != EScreens.ScreenSing) CSongs.LoadCover(30L, 1); if (CSettings.GameState != EGameState.EditTheme) @@ -323,12 +349,13 @@ namespace Vocaluxe.Menu public static bool Draw() { - if ((NextScreen != EScreens.ScreenNull) && !_Fading) + if ((_NextScreen != EScreens.ScreenNull) && !_Fading) { _Fading = true; _FadingTimer.Reset(); _FadingTimer.Start(); - Screens[(int)NextScreen].OnShow(); + _Screens[(int)_NextScreen].OnShow(); + HidePopup(EPopupScreens.PopupPlayerControl); } if (_Fading) @@ -345,30 +372,38 @@ namespace Vocaluxe.Menu _GlobalAlpha = 1f;// -factor / 100f; _ZOffset = CSettings.zFar/2; - Screens[(int)ActualScreen].Draw(); + _Screens[(int)_CurrentScreen].Draw(); _GlobalAlpha = factor; _ZOffset = 0f; - Screens[(int)NextScreen].Draw(); + _Screens[(int)_NextScreen].Draw(); _GlobalAlpha = 1f; } else { - Screens[(int)ActualScreen].OnClose(); - ActualScreen = NextScreen; - NextScreen = EScreens.ScreenNull; - Screens[(int)ActualScreen].OnShowFinish(); - Screens[(int)ActualScreen].ProcessMouseMove(_Cursor.X, _Cursor.Y); - Screens[(int)ActualScreen].Draw(); + _Screens[(int)_CurrentScreen].OnClose(); + _CurrentScreen = _NextScreen; + _NextScreen = EScreens.ScreenNull; + if(CBackgroundMusic.Playing) + CBackgroundMusic.Play(); + _Screens[(int)_CurrentScreen].OnShowFinish(); + _Screens[(int)_CurrentScreen].ProcessMouseMove(_Cursor.X, _Cursor.Y); + _Screens[(int)_CurrentScreen].Draw(); _Fading = false; _FadingTimer.Stop(); } } else { - Screens[(int)ActualScreen].Draw(); + _Screens[(int)_CurrentScreen].Draw(); } + + for (int i = 0; i < _PopupScreens.Count; i++) + { + _PopupScreens[i].Draw(); + } + _Cursor.Draw(); DrawDebugInfos(); @@ -377,7 +412,23 @@ namespace Vocaluxe.Menu public static void FadeTo(EScreens Screen) { - NextScreen = Screen; + _NextScreen = Screen; + } + + public static void ShowPopup(EPopupScreens PopupScreen) + { + _PopupScreens[(int)PopupScreen].OnShow(); + _PopupScreens[(int)PopupScreen].OnShowFinish(); + _CurrentPopupScreen = PopupScreen; + } + + public static void HidePopup(EPopupScreens PopupScreen) + { + if (_CurrentPopupScreen != PopupScreen) + return; + + _PopupScreens[(int)PopupScreen].OnClose(); + _CurrentPopupScreen = EPopupScreens.NoPopup; } public static void HideCursor() @@ -398,6 +449,9 @@ namespace Vocaluxe.Menu KeyEvent KeyEvent = new KeyEvent(); MouseEvent MouseEvent = new MouseEvent(); + bool PopupPlayerControlAllowed = _CurrentScreen != EScreens.ScreenOptionsRecord && _CurrentScreen != EScreens.ScreenSing && _CurrentScreen != EScreens.ScreenNames + && _CurrentScreen != EScreens.ScreenSong; + bool Resume = true; while (keys.PollEvent(ref KeyEvent)) { @@ -406,6 +460,14 @@ namespace Vocaluxe.Menu CSettings.MouseInacive(); _Cursor.FadeOut(); } + + if (PopupPlayerControlAllowed && KeyEvent.Key == Keys.Tab) + { + if (_CurrentPopupScreen == EPopupScreens.NoPopup) + ShowPopup(EPopupScreens.PopupPlayerControl); + else + HidePopup(EPopupScreens.PopupPlayerControl); + } if (KeyEvent.ModSHIFT && (KeyEvent.Key == Keys.F1)) { @@ -422,7 +484,14 @@ namespace Vocaluxe.Menu else { if (!_Fading) - Resume &= Screens[(int)ActualScreen].HandleInput(KeyEvent); + { + bool handled = false; + if (_CurrentPopupScreen != EPopupScreens.NoPopup) + handled = _PopupScreens[(int)_CurrentPopupScreen].HandleInput(KeyEvent); + + if (!handled) + Resume &= _Screens[(int)_CurrentScreen].HandleInput(KeyEvent); + } } } @@ -436,8 +505,22 @@ namespace Vocaluxe.Menu UpdateMousePosition(MouseEvent.X, MouseEvent.Y); - if (!_Fading && (_Cursor.IsActive || MouseEvent.LB || MouseEvent.RB)) - Resume &= Screens[(int)ActualScreen].HandleMouse(MouseEvent); + bool isOverPopupPlayerControl = CHelper.IsInBounds(_PopupScreens[(int)EPopupScreens.PopupPlayerControl].ScreenArea, MouseEvent); + if (PopupPlayerControlAllowed && isOverPopupPlayerControl) + { + if (_CurrentPopupScreen == EPopupScreens.NoPopup) + ShowPopup(EPopupScreens.PopupPlayerControl); + } + + if (!isOverPopupPlayerControl && _CurrentPopupScreen == EPopupScreens.PopupPlayerControl) + HidePopup(EPopupScreens.PopupPlayerControl); + + bool handled = false; + if (_CurrentPopupScreen != EPopupScreens.NoPopup) + handled = _PopupScreens[(int)_CurrentPopupScreen].HandleMouse(MouseEvent); + + if (!handled && !_Fading && (_Cursor.IsActive || MouseEvent.LB || MouseEvent.RB)) + Resume &= _Screens[(int)_CurrentScreen].HandleMouse(MouseEvent); } return Resume; } @@ -452,7 +535,7 @@ namespace Vocaluxe.Menu if (KeyEvent.ModSHIFT && (KeyEvent.Key == Keys.F1)) { CSettings.GameState = EGameState.Normal; - Screens[(int)ActualScreen].NextInteraction(); + _Screens[(int)_CurrentScreen].NextInteraction(); } else if (KeyEvent.ModALT && (KeyEvent.Key == Keys.Enter)) { @@ -465,14 +548,14 @@ namespace Vocaluxe.Menu else { if (!_Fading) - Screens[(int)ActualScreen].HandleInputThemeEditor(KeyEvent); + _Screens[(int)_CurrentScreen].HandleInputThemeEditor(KeyEvent); } } while (Mouse.PollEvent(ref MouseEvent)) { if (!_Fading) - Screens[(int)ActualScreen].HandleMouseThemeEditor(MouseEvent); + _Screens[(int)_CurrentScreen].HandleMouseThemeEditor(MouseEvent); UpdateMousePosition(MouseEvent.X, MouseEvent.Y); } @@ -486,7 +569,9 @@ namespace Vocaluxe.Menu private static bool Update() { - return Screens[(int)ActualScreen].UpdateGame(); + if (_CurrentPopupScreen != EPopupScreens.NoPopup) + _PopupScreens[(int)_CurrentPopupScreen].UpdateGame(); + return _Screens[(int)_CurrentScreen].UpdateGame(); } private static void DrawDebugInfos() diff --git a/Vocaluxe/Menu/CLyric.cs b/Vocaluxe/Menu/CLyric.cs index 8a70e0ab..5cabd507 100644 --- a/Vocaluxe/Menu/CLyric.cs +++ b/Vocaluxe/Menu/CLyric.cs @@ -11,14 +11,6 @@ using Vocaluxe.Lib.Song; namespace Vocaluxe.Menu { - enum ELyricStyle - { - Fill, - Jump, - Slide, - Zoom - } - struct SNote { public string Text; @@ -84,6 +76,12 @@ namespace Vocaluxe.Menu } } + public ELyricStyle LyricStyle + { + get { return _Style; } + set { _Style = value; } + } + public CLyric() { _Theme = new SThemeLyrics(); @@ -100,7 +98,7 @@ namespace Vocaluxe.Menu _Notes = new List(); _Text = new CText(); - _Style = ELyricStyle.Slide; + _Style = ELyricStyle.Fill; } public bool LoadTheme(string XmlPath, string ElementName, XPathNavigator navigator, int SkinIndex) diff --git a/Vocaluxe/Menu/CMenu.cs b/Vocaluxe/Menu/CMenu.cs index 8effd14a..1f575399 100644 --- a/Vocaluxe/Menu/CMenu.cs +++ b/Vocaluxe/Menu/CMenu.cs @@ -62,6 +62,13 @@ namespace Vocaluxe.Menu protected string[] _ThemeSingNotes; protected string[] _ThemeNameSelections; + protected SRectF _ScreenArea; + + public SRectF ScreenArea + { + get { return _ScreenArea; } + } + public int ThemeScreenVersion { get { return _ScreenVersion; } @@ -104,6 +111,7 @@ namespace Vocaluxe.Menu _MouseDY = 0; _Active = false; + _ScreenArea = new SRectF(0f, 0f, CSettings.iRenderW, CSettings.iRenderH, 0f); _ThemeName = String.Empty; _ThemeBackgrounds = null; @@ -928,13 +936,12 @@ namespace Vocaluxe.Menu { ResumeBG(); _Active = true; - CBackgroundMusic.Play(); } public virtual void OnClose() { PauseBG(); - CBackgroundMusic.Pause(); + _Active = false; } #endregion MenuHandler diff --git a/Vocaluxe/Screens/CPopupScreenPlayerControl.cs b/Vocaluxe/Screens/CPopupScreenPlayerControl.cs new file mode 100644 index 00000000..85e1467d --- /dev/null +++ b/Vocaluxe/Screens/CPopupScreenPlayerControl.cs @@ -0,0 +1,229 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Windows.Forms; + +using Vocaluxe.Base; +using Vocaluxe.Lib.Draw; +using Vocaluxe.Menu; +using Vocaluxe.Lib.Song; + +namespace Vocaluxe.Screens +{ + class CPopupScreenPlayerControl : CMenu + { + // Version number for theme files. Increment it, if you've changed something on the theme files! + const int ScreenVersion = 1; + + private const string StaticBG = "StaticBG"; + private const string StaticCover = "StaticCover"; + + private const string ButtonPrevious = "ButtonPrevious"; + private const string ButtonPlay = "ButtonPlay"; + private const string ButtonPause = "ButtonPause"; + private const string ButtonNext = "ButtonNext"; + private const string ButtonRepeat = "ButtonRepeat"; + private const string ButtonShowVideo = "ButtonShowVideo"; + private const string ButtonSing = "ButtonSing"; + private const string ButtonToBackgroundVideo = "ButtonToBackgroundVideo"; + + private const string TextCurrentSong = "TextCurrentSong"; + private bool _VideoPreview = false; + + private bool VideoPreview + { + get + { + return _VideoPreview; + } + set + { + _VideoPreview = value; + if (!_VideoPreview && !VideoBackground) + CBackgroundMusic.VideoEnabled = false; + else + CBackgroundMusic.VideoEnabled = true; + } + } + + private bool VideoBackground + { + get + { + return CConfig.VideosToBackground == EOffOn.TR_CONFIG_ON; + } + set + { + if (!value) + { + if (CConfig.VideosToBackground == EOffOn.TR_CONFIG_ON) + { + CConfig.VideosToBackground = EOffOn.TR_CONFIG_OFF; + if (!_VideoPreview) + CBackgroundMusic.VideoEnabled = false; + } + } + else + { + CConfig.VideosToBackground = EOffOn.TR_CONFIG_ON; + CBackgroundMusic.VideoEnabled = true; + } + CConfig.SaveConfig(); + } + } + + public CPopupScreenPlayerControl() + { + Init(); + } + + protected override void Init() + { + base.Init(); + + _ThemeName = "PopupScreenPlayerControl"; + _ScreenVersion = ScreenVersion; + + _ThemeStatics = new string[] { StaticBG, StaticCover }; + _ThemeTexts = new string[] { TextCurrentSong }; + + List buttons = new List(); + buttons.Add(ButtonPlay); + buttons.Add(ButtonPause); + buttons.Add(ButtonPrevious); + buttons.Add(ButtonNext); + buttons.Add(ButtonRepeat); + buttons.Add(ButtonShowVideo); + buttons.Add(ButtonSing); + buttons.Add(ButtonToBackgroundVideo); + _ThemeButtons = buttons.ToArray(); + } + + public override void LoadTheme() + { + base.LoadTheme(); + + _ScreenArea = Statics[htStatics(StaticBG)].Rect; + } + + public override bool HandleInput(KeyEvent KeyEvent) + { + base.HandleInput(KeyEvent); + if (KeyEvent.KeyPressed && !Char.IsControl(KeyEvent.Unicode)) + { + + } + else + { + switch (KeyEvent.Key) + { + case Keys.Escape: + case Keys.Back: + CGraphics.HidePopup(EPopupScreens.PopupPlayerControl); + return false; + + case Keys.Enter: + if (Buttons[htButtons(ButtonNext)].Selected) + CBackgroundMusic.Next(); + if (Buttons[htButtons(ButtonPrevious)].Selected) + CBackgroundMusic.Previous(); + if (Buttons[htButtons(ButtonPlay)].Selected) + CBackgroundMusic.Play(); + if (Buttons[htButtons(ButtonPause)].Selected) + CBackgroundMusic.Pause(); + if (Buttons[htButtons(ButtonRepeat)].Selected) + CBackgroundMusic.Repeat(); + if (Buttons[htButtons(ButtonShowVideo)].Selected) + VideoPreview = !VideoPreview; + if (Buttons[htButtons(ButtonSing)].Selected) + StartSong(CBackgroundMusic.SongID, CBackgroundMusic.Duet); + if (Buttons[htButtons(ButtonToBackgroundVideo)].Selected) + VideoBackground = !VideoBackground; + break; + } + } + + return true; + } + + public override bool HandleMouse(MouseEvent MouseEvent) + { + base.HandleMouse(MouseEvent); + if (MouseEvent.LB && IsMouseOver(MouseEvent)) + { + if (Buttons[htButtons(ButtonNext)].Selected) + CBackgroundMusic.Next(); + if (Buttons[htButtons(ButtonPrevious)].Selected) + CBackgroundMusic.Previous(); + if (Buttons[htButtons(ButtonPlay)].Selected) + CBackgroundMusic.Play(); + if (Buttons[htButtons(ButtonPause)].Selected) + CBackgroundMusic.Pause(); + if (Buttons[htButtons(ButtonRepeat)].Selected) + CBackgroundMusic.Repeat(); + if (Buttons[htButtons(ButtonShowVideo)].Selected) + VideoPreview = !VideoPreview; + if (Buttons[htButtons(ButtonSing)].Selected) + StartSong(CBackgroundMusic.SongID, CBackgroundMusic.Duet); + if (Buttons[htButtons(ButtonToBackgroundVideo)].Selected) + VideoBackground = !VideoBackground; + } else if (MouseEvent.LB) + { + //CGraphics.HidePopup(EPopupScreens.PopupPlayerControl); + return false; + } else if (MouseEvent.RB) + { + //CGraphics.HidePopup(EPopupScreens.PopupPlayerControl); + return false; + } + return true; + } + + public override bool UpdateGame() + { + + Statics[htStatics(StaticCover)].Visible = !_VideoPreview || !CBackgroundMusic.SongHasVideo; + Buttons[htButtons(ButtonToBackgroundVideo)].Pressed = VideoBackground; + Buttons[htButtons(ButtonShowVideo)].Pressed = _VideoPreview; + Buttons[htButtons(ButtonSing)].Visible = CBackgroundMusic.CanSing; + return true; + } + + public override void OnShow() + { + base.OnShow(); + } + + public override bool Draw() + { + if (!_Active) + return false; + Statics[htStatics(StaticCover)].Texture = CBackgroundMusic.Cover; + if (CBackgroundMusic.VideoEnabled && VideoPreview && CBackgroundMusic.SongHasVideo) + CDraw.DrawTexture(Statics[htStatics(StaticCover)], CBackgroundMusic.GetVideoTexture(), EAspect.Crop); + Buttons[htButtons(ButtonPause)].Visible = CBackgroundMusic.Playing; + Buttons[htButtons(ButtonPlay)].Visible = !CBackgroundMusic.Playing; + Texts[htTexts(TextCurrentSong)].Text = CBackgroundMusic.ArtistAndTitle; + + return base.Draw(); + } + + private void StartSong(int SongNr, bool Duet) + { + if (SongNr >= 0 && CSongs.SongsLoaded) + { + if (Duet) + CGame.SetGameMode(GameModes.EGameMode.Duet); + else + CGame.SetGameMode(GameModes.EGameMode.Normal); + + CGame.Reset(); + CGame.ClearSongs(); + CGame.AddSong(SongNr); + + CGraphics.FadeTo(EScreens.ScreenNames); + } + } + } +} diff --git a/Vocaluxe/Screens/CScreenLoad.cs b/Vocaluxe/Screens/CScreenLoad.cs index a38f6810..5e74e834 100644 --- a/Vocaluxe/Screens/CScreenLoad.cs +++ b/Vocaluxe/Screens/CScreenLoad.cs @@ -120,6 +120,9 @@ namespace Vocaluxe.Screens _Intros[i].Load(IntroVideo[i]); } } + + if (!CBackgroundMusic.Playing) + CBackgroundMusic.Next(); } public override void OnShowFinish() @@ -139,7 +142,7 @@ namespace Vocaluxe.Screens _SongLoaderThread.Start(); _timer.Start(); - if (!CBackgroundMusic.IsPlaying()) + if (!CBackgroundMusic.Playing) CBackgroundMusic.Next(); } @@ -173,9 +176,10 @@ namespace Vocaluxe.Screens { CBackgroundMusic.AddOwnMusic(); - if (!CBackgroundMusic.IsPlaying()) - CBackgroundMusic.Next(); + //if (!CBackgroundMusic.Playing) + // CBackgroundMusic.Next(); } + CBackgroundMusic.CanSing = false; return true; } @@ -204,6 +208,8 @@ namespace Vocaluxe.Screens _Intros[i].Close(); } + CBackgroundMusic.CanSing = true; + CLog.StopBenchmark(3, "Load Cover"); } diff --git a/Vocaluxe/Screens/CScreenMain.cs b/Vocaluxe/Screens/CScreenMain.cs index e558cf24..76dd28c0 100644 --- a/Vocaluxe/Screens/CScreenMain.cs +++ b/Vocaluxe/Screens/CScreenMain.cs @@ -65,14 +65,14 @@ namespace Vocaluxe.Screens CGraphics.FadeTo(EScreens.ScreenSong); break; - case Keys.T: - CGraphics.FadeTo(EScreens.ScreenTest); - break; - case Keys.C: CGraphics.FadeTo(EScreens.ScreenCredits); break; + case Keys.T: + CGraphics.FadeTo(EScreens.ScreenTest); + break; + case Keys.Enter: if (Buttons[htButtons(ButtonSing)].Selected) CGraphics.FadeTo(EScreens.ScreenSong); diff --git a/Vocaluxe/Screens/CScreenOptionsRecord.cs b/Vocaluxe/Screens/CScreenOptionsRecord.cs index 4426b7af..2198e506 100644 --- a/Vocaluxe/Screens/CScreenOptionsRecord.cs +++ b/Vocaluxe/Screens/CScreenOptionsRecord.cs @@ -51,6 +51,8 @@ namespace Vocaluxe.Screens private bool _DelayTestRunning; private int _DelaySound; + private Equalizer[] _Equalizer; + public CScreenOptionsRecord() { Init(); @@ -254,7 +256,8 @@ namespace Vocaluxe.Screens _DelayTest[i].Timer.Stop(); _DelayTestRunning = false; } - else if (CSound.RecordGetMaxVolume(player - 1) > 0.4f && CSound.RecordGetToneAbs(player - 1) == 9) + else if (CSound.RecordGetMaxVolume(player - 1) > 0.1f && + (CSound.RecordGetToneAbs(player - 1) == 9 || CSound.RecordGetToneAbs(player - 1) == 21 || CSound.RecordGetToneAbs(player - 1) == 33)) { _DelayTest[i].Delay = _DelayTest[i].Timer.ElapsedMilliseconds; _DelayTest[i].Timer.Stop(); @@ -274,20 +277,27 @@ namespace Vocaluxe.Screens if (player > 0) { ChannelEnergy[0] = CSound.RecordGetMaxVolume(player - 1); + _Equalizer[0].Update(CSound.ToneWeigth(player - 1)); } + else + _Equalizer[0].Reset(); ChannelEnergy[1] = 0f; player = SelectSlides[htSelectSlides(SelectSlideRecordChannel2)].Selection; if (player > 0) { ChannelEnergy[1] = CSound.RecordGetMaxVolume(player - 1); + _Equalizer[1].Update(CSound.ToneWeigth(player - 1)); } + else + _Equalizer[1].Reset(); } else { for (int i = 0; i < ChannelEnergy.Length; i++) { ChannelEnergy[i] = 0f; + _Equalizer[i].Reset(); } } @@ -351,6 +361,13 @@ namespace Vocaluxe.Screens _DelayTestRunning = false; _DelaySound = -1; + + _Equalizer = new Equalizer[2]; + + for (int i = 0; i < _Equalizer.Length; i++) + { + _Equalizer[i] = new Equalizer(new SRectF(50 + 350 * i, 400, 230, 150, -1), CSound.NumHalfTones(0), 2); + } } public override void OnShowFinish() @@ -389,6 +406,11 @@ namespace Vocaluxe.Screens } } + for (int i = 0; i < _Equalizer.Length; i++) + { + _Equalizer[i].Draw(); + } + DrawFG(); return true; @@ -571,4 +593,88 @@ namespace Vocaluxe.Screens } } } + + class Equalizer + { + + private SRectF _Bounds; + private float _Space; + + private float[] _Bars; + + public Equalizer(SRectF bounds, int numBars, float space) + { + _Bounds = bounds; + _Space = space; + + if (numBars > 0) + _Bars = new float[numBars]; + } + + public void Update(float[] weights) + { + if (weights == null || weights.Length == 0 || _Bars == null) + return; + + if (_Bars.Length < weights.Length) + { + } + else if (_Bars.Length > weights.Length) + { + } + else + { + for (int i = 0; i < _Bars.Length; i++) + { + //if (weights[i] > 0) + _Bars[i] = weights[i]; + //else + // _Bars[i] = 0f; + } + } + } + + public void Reset() + { + if (_Bars == null || _Bars.Length == 0) + return; + + for (int i = 0; i < _Bars.Length; i++) + { + _Bars[i] = 0f; + } + } + + public void Draw() + { + if (_Bars == null) + return; + + float dx = _Bounds.W / _Bars.Length + _Space; + int max = _Bars.Length - 1; + float maxB = _Bars[max]; + for (int i = 0; i < _Bars.Length - 1; i++) + { + if (_Bars[i] > maxB) + { + maxB = _Bars[i]; + max = i; + } + } + + + for (int i = 0; i < _Bars.Length; i++) + { + SRectF bar = new SRectF(_Bounds.X + dx * i, _Bounds.Y + _Bounds.H - _Bars[i] * _Bounds.H, dx - _Space, _Bars[i] * _Bounds.H, _Bounds.Z); + SColorF color = new SColorF(1f, 1f, 1f, 1f); + if (i == max) + { + color.B = 0f; + color.G = 0f; + } + + CDraw.DrawColor(color, bar); + } + } + } } diff --git a/Vocaluxe/Screens/CScreenOptionsVideo.cs b/Vocaluxe/Screens/CScreenOptionsVideo.cs index 04e9d4e1..fd693db6 100644 --- a/Vocaluxe/Screens/CScreenOptionsVideo.cs +++ b/Vocaluxe/Screens/CScreenOptionsVideo.cs @@ -12,11 +12,12 @@ namespace Vocaluxe.Screens class CScreenOptionsVideo : 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 SelectSlideVideoBackgrounds = "SelectSlideVideoBackgrounds"; private const string SelectSlideVideoPreview = "SelectSlideVideoPreview"; private const string SelectSlideVideosInSongs = "SelectSlideVideosInSongs"; + private const string SelectSlideVideosToBackground = "SelectSlideVideosToBackground"; private const string ButtonExit = "ButtonExit"; @@ -33,7 +34,7 @@ namespace Vocaluxe.Screens _ScreenVersion = ScreenVersion; _ThemeButtons = new string[] { ButtonExit }; - _ThemeSelectSlides = new string[] { SelectSlideVideoBackgrounds, SelectSlideVideoPreview, SelectSlideVideosInSongs }; + _ThemeSelectSlides = new string[] { SelectSlideVideoBackgrounds, SelectSlideVideoPreview, SelectSlideVideosInSongs, SelectSlideVideosToBackground }; } public override void LoadTheme() @@ -43,6 +44,7 @@ namespace Vocaluxe.Screens SelectSlides[htSelectSlides(SelectSlideVideoBackgrounds)].SetValues((int)CConfig.VideoBackgrounds); SelectSlides[htSelectSlides(SelectSlideVideoPreview)].SetValues((int)CConfig.VideoPreview); SelectSlides[htSelectSlides(SelectSlideVideosInSongs)].SetValues((int)CConfig.VideosInSongs); + SelectSlides[htSelectSlides(SelectSlideVideosToBackground)].SetValues((int)CConfig.VideosToBackground); } public override bool HandleInput(KeyEvent KeyEvent) @@ -110,6 +112,7 @@ namespace Vocaluxe.Screens public override bool UpdateGame() { + SelectSlides[htSelectSlides(SelectSlideVideosToBackground)].Selection = (int)CConfig.VideosToBackground; return true; } @@ -124,6 +127,8 @@ namespace Vocaluxe.Screens CConfig.VideoBackgrounds = (EOffOn)SelectSlides[htSelectSlides(SelectSlideVideoBackgrounds)].Selection; CConfig.VideoPreview = (EOffOn)SelectSlides[htSelectSlides(SelectSlideVideoPreview)].Selection; CConfig.VideosInSongs = (EOffOn)SelectSlides[htSelectSlides(SelectSlideVideosInSongs)].Selection; + CConfig.VideosToBackground = (EOffOn)SelectSlides[htSelectSlides(SelectSlideVideosToBackground)].Selection; + CBackgroundMusic.VideoEnabled = true; CConfig.SaveConfig(); } diff --git a/Vocaluxe/Screens/CScreenSing.cs b/Vocaluxe/Screens/CScreenSing.cs index e8a453f9..2ddd87dd 100644 --- a/Vocaluxe/Screens/CScreenSing.cs +++ b/Vocaluxe/Screens/CScreenSing.cs @@ -359,10 +359,17 @@ namespace Vocaluxe.Screens NoteLines[i] = -1; } + for (int i = 0; i < Lyrics.Length; i++) + { + Lyrics[i].LyricStyle = CConfig.LyricStyle; + } SetVisuability(); + UpdateAvatars(); UpdateNames(); - CBackgroundMusic.Pause(); + + CBackgroundMusic.Disabled = true; + } public override void OnShowFinish() @@ -371,7 +378,7 @@ namespace Vocaluxe.Screens CGame.Start(); LoadNextSong(); - CBackgroundMusic.Pause(); + CBackgroundMusic.Disabled = true; } public override bool Draw() @@ -454,6 +461,7 @@ namespace Vocaluxe.Screens public override void OnClose() { base.OnClose(); + CBackgroundMusic.Disabled = false; CloseSong(); } diff --git a/Vocaluxe/Screens/CScreenSong.cs b/Vocaluxe/Screens/CScreenSong.cs index d0f72677..df176860 100644 --- a/Vocaluxe/Screens/CScreenSong.cs +++ b/Vocaluxe/Screens/CScreenSong.cs @@ -187,12 +187,12 @@ namespace Vocaluxe.Screens if ((CSongs.Category >= 0 || CConfig.Tabs == EOffOn.TR_CONFIG_OFF) && song >= 0 && song < CSongs.VisibleSongs.Length) { Texts[htTexts(TextSelection)].Text = CSongs.VisibleSongs[song].Artist + " - " + CSongs.VisibleSongs[song].Title; - CBackgroundMusic.Pause(); + CBackgroundMusic.Disabled = true; } else if (CSongs.Category == -1 && song >= 0 && song < CSongs.Categories.Length) { Texts[htTexts(TextSelection)].Text = CSongs.Categories[song].Name; - CBackgroundMusic.Play(); + CBackgroundMusic.Disabled = false; } else Texts[htTexts(TextSelection)].Text = String.Empty; @@ -227,6 +227,7 @@ namespace Vocaluxe.Screens public override void OnClose() { base.OnClose(); + CBackgroundMusic.Disabled = false; SongMenus[htSongMenus(SongMenu)].OnHide(); } @@ -351,4 +352,4 @@ namespace Vocaluxe.Screens SongMenus[htSongMenus(SongMenu)].OnShow(); } } -} \ No newline at end of file +} diff --git a/Vocaluxe/Screens/CScreenTest.cs b/Vocaluxe/Screens/CScreenTest.cs index 277b96cc..9f387043 100644 --- a/Vocaluxe/Screens/CScreenTest.cs +++ b/Vocaluxe/Screens/CScreenTest.cs @@ -50,15 +50,15 @@ namespace Vocaluxe.Screens break; case Keys.F: - FadeAndPause(); + //FadeAndPause(); break; case Keys.S: - PlayFile(); + //PlayFile(); break; case Keys.P: - PauseFile(); + //PauseFile(); break; } } diff --git a/Vocaluxe/Vocaluxe.csproj b/Vocaluxe/Vocaluxe.csproj index 6dc4fbe4..e8282b61 100644 --- a/Vocaluxe/Vocaluxe.csproj +++ b/Vocaluxe/Vocaluxe.csproj @@ -148,6 +148,7 @@ + @@ -188,6 +189,7 @@ Form +